ServiceNow Debugging Techniques
SkillDev toolsComprehensive guide to debugging ServiceNow server-side and client-side code
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the ServiceNow Debugging Techniques skill
What this skill tells your AI
The instructions your AI receives, as published by happy-technologies-llc/happy-platform-skills in skills/development/debugging-techniques/SKILL.md and read by ahel’s review.
Overview
Master the art of debugging ServiceNow applications using built-in tools and techniques. This skill covers server-side debugging, client-side debugging, log analysis, and common error resolution.
- What problem does it solve? Identifies and resolves issues in business rules, script includes, client scripts, workflows, and flows
- Who should use this skill? ServiceNow developers, administrators, and support engineers
- What are the expected outcomes? Faster issue identification, efficient troubleshooting, and cleaner code
Prerequisites
- Required ServiceNow roles:
adminorscript_writefor Script Debugger - Access to System Logs (System Logs > All)
- Browser Developer Tools knowledge (Chrome DevTools, Firefox Developer Tools)
- Understanding of JavaScript fundamentals
Procedure
Server-Side Debugging
Logging Functions
ServiceNow provides multiple logging functions for server-side scripts. Choose based on log level and visibility requirements.
| Function | Log Level | Use Case |
|---|---|---|
gs.log(message, source) | Debug | Development/testing - legacy, prefer gs.debug |
gs.debug(message) | Debug | Detailed troubleshooting (requires debug enabled) |
gs.info(message) | Info | Informational messages for normal operations |
gs.warn(message) | Warning | Potential issues that don't stop execution |
gs.error(message) | Error | Errors that need attention |
Best Practice: Always include context in log messages:
// BAD - No context
gs.info('Record updated');
// GOOD - Full context
gs.info('[IncidentHandler] Incident ' + current.number + ' updated by ' + gs.getUserName() +
' - State changed from ' + current.state.getDisplayValue() + ' to ' + previous.state.getDisplayValue());
Querying System Logs:
Tool: SN-Query-Table
Parameters:
table_name: syslog
query: source=IncidentHandler^sys_created_onONToday@javascript:gs.beginningOfToday()@javascript:gs.endOfToday()
fields: sys_created_on,level,message,source
limit: 50
order_by: sys_created_on
order_by_desc: true
Script Debugger
The Script Debugger allows step-by-step execution of server-side scripts.
Enabling the Script Debugger:
- Navigate to System Diagnostics > Script Debugger
- Click Enable Debugging for your session
- Set breakpoints in scripts using the debugger UI
- Trigger the script (e.g., update a record)
- Step through code using F10 (step over), F11 (step into), F5 (continue)
Debugging Business Rules:
Tool: SN-Query-Table
Parameters:
table_name: sys_script
query: collection=incident^active=true
fields: name,order,when,script,condition
limit: 50
order_by: order
Key Features:
- Variable inspection (hover over variables)
- Call stack visualization
- Watch expressions
- Conditional breakpoints
Session Debug Modules
Enable detailed logging for specific components during your session.
Common Session Debug Modules:
| Module | Purpose | Enable Path |
|---|---|---|
Session Debug | All session debugging | System Diagnostics > Session Debug > All |
Business Rules | Log BR execution | System Diagnostics > Session Debug > Business Rules |
SQL | Log database queries | System Diagnostics > Session Debug > SQL |
Security | ACL debugging | System Diagnostics > Session Debug > Security |
Client Scripts | Log client script data | System Diagnostics > Session Debug > Client Scripts |
Enable via Script:
// Enable business rule debugging for current session
gs.setProperty('glide.debugger.current.enabled', 'true');
Script Execution History
Track script execution for troubleshooting.
Tool: SN-Query-Table
Parameters:
table_name: sys_script_execution_history
query: sys_created_onONLast 1 hour@javascript:gs.hoursAgo(1)@javascript:gs.nowDateTime()
fields: script,execution_time,status,error_message,sys_created_on
limit: 100
order_by: sys_created_on
order_by_desc: true
Client-Side Debugging
Browser Console Methods
| Method | Purpose |
|---|---|
console.log() | General logging |
console.info() | Informational messages |
console.warn() | Warning messages |
console.error() | Error messages |
console.table() | Display data in table format |
console.trace() | Show call stack |
ServiceNow-Specific:
// jslog - ServiceNow legacy logging (outputs to console when enabled)
jslog('Client script executed: ' + g_form.getValue('number'));
// Check if debug mode is enabled
if (window.NOW && NOW.debug) {
console.log('[DEBUG] Form loaded for: ' + g_form.getValue('sys_id'));
}
Browser DevTools Debugging
Chrome DevTools Workflow:
- Open DevTools (F12 or Cmd+Option+I)
- Navigate to Sources tab
- Find client scripts under
scripts.do?sysparm_type=or in the page source - Set breakpoints by clicking line numbers
- Use Watch panel to monitor variables
- Use Scope panel to inspect local/closure variables
Useful DevTools Commands:
// In Console - Inspect form field
g_form.getValue('short_description');
// Get all form values
g_form.serialize();
// Check if field is mandatory
g_form.isMandatory('priority');
// Inspect GlideAjax response
// Set breakpoint in callback function to inspect 'response' object
Network Tab Analysis
Monitor AJAX calls and API requests:
- Open DevTools > Network tab
- Filter by XHR/Fetch
- Look for calls to:
xmlhttp.do- GlideAjax callsapi/now/- REST API callssysparm_processor- Form submissions
Common Network Issues:
- 401/403 errors - Authentication/ACL issues
- 500 errors - Server-side script errors
- Slow responses - Check Timing tab for breakdown
Transaction Logs
Analyzing Transaction Performance
Tool: SN-Query-Table
Parameters:
table_name: syslog_transaction
query: sys_created_onONLast 1 hour@javascript:gs.hoursAgo(1)@javascript:gs.nowDateTime()^urlLIKEincident
fields: url,response_time,user,sys_created_on,status
limit: 50
order_by: response_time
order_by_desc: true
Slow Query Detection
Tool: SN-Query-Table
Parameters:
table_name: syslog
query: messageLIKEslow query^sys_created_onONToday@javascript:gs.beginningOfToday()@javascript:gs.endOfToday()
fields: sys_created_on,message,source
limit: 100
Debugging Business Rules
Understanding Business Rule Execution Order
Business rules execute in this order for each operation (insert, update, delete):
- before rules (order ascending) - Execute before database write
- after rules (order ascending) - Execute after database write
- async rules - Execute asynchronously
Critical: Order Matters!
Tool: SN-Query-Table
Parameters:
table_name: sys_script
query: collection=incident^active=true^when=before
fields: name,order,when,condition,script
limit: 100
order_by: order
Debugging Order Issues:
// Add to each business rule to trace execution order
gs.info('[BR Debug] ' + current.sys_class_name + ' - ' +
'Name: ' + current.getTableName() + '_BR_Name - ' +
'Order: ' + 100 + ' - ' +
'When: before - ' +
'Record: ' + current.number);
Common Business Rule Debugging Patterns
Check if Script is Running:
(function executeRule(current, previous) {
gs.info('[BR_NAME] Script starting for: ' + current.getDisplayValue());
// Your logic here
gs.info('[BR_NAME] Script completed');
})(current, previous);
Debug Condition:
// Log condition evaluation
gs.info('[BR_NAME] Condition check - current.state: ' + current.state +
', previous.state: ' + previous.state +
', Result: ' + (current.state != previous.state));
Inspect Current vs Previous:
// Log all changed fields
var changes = current.changesLog();
if (changes) {
gs.info('[BR_NAME] Changes: ' + changes);
}
Debugging Workflows and Flows
Workflow Debugging
Query Workflow Context:
Tool: SN-Query-Table
Parameters:
table_name: wf_context
query: active=true
fields: name,state,started,ended,id,scratchpad
limit: 50
order_by: sys_created_on
order_by_desc: true
Check Workflow History:
Tool: SN-Query-Table
Parameters:
table_name: wf_history
query: context.active=false^sys_created_onONLast 7 days@javascript:gs.daysAgo(7)@javascript:gs.nowDateTime()
fields: activity,from_state,to_state,additional_info,sys_created_on
limit: 100
order_by: sys_created_on
order_by_desc: true
Flow Designer Debugging
Query Flow Executions:
Tool: SN-Query-Table
Parameters:
table_name: sys_flow_context
query: state!=complete^ORstate=error
fields: name,state,started,ended,error_message
limit: 50
order_by: sys_created_on
order_by_desc: true
Enable Flow Debug Mode:
- Open the flow in Flow Designer
- Click More Actions (three dots) > Debug
- Trigger the flow
- Review execution in the Debug panel
Common Error Messages and Solutions
"Record not found in table"
Cause: GlideRecord query returned no results Solution:
var gr = new GlideRecord('incident');
gr.addQuery('number', 'INC0000001');
gr.query();
if (gr.next()) {
// Record found
} else {
gs.warn('Record not found: INC0000001');
}
"User not authorized"
Cause: ACL blocking access Solution:
- Enable Session Debug > Security
- Check ACL logs: System Logs > Security
- Query ACLs:
Tool: SN-Query-Table
Parameters:
table_name: sys_security_acl
query: name=incident
fields: name,operation,condition,script,role
limit: 100
"Invalid script" or "Script error"
Cause: JavaScript syntax error or runtime exception Solution:
- Check System Logs for stack trace
- Use Script Debugger to step through
- Validate syntax with browser console
"Maximum execution time exceeded"
Cause: Script running too long (30+ seconds) Solution:
- Add GlideAggregate for counting instead of looping
- Use setLimit() to restrict result sets
- Move to Scheduled Job for large operations
"Mutual exclusion violation"
Cause: Same record being updated by multiple processes Solution:
- Check for recursive business rules
- Add condition to prevent re-entry:
if (current.update_in_progress) return;
current.update_in_progress = true;
"Nested call limit exceeded"
Cause: Too many nested GlideRecord operations or recursive calls Solution:
- Refactor to reduce nesting depth
- Use GlideAggregate for counts
- Break into separate transactions
Tool Usage
MCP Tools (Claude Code/Desktop)
| Tool | Purpose |
|---|---|
SN-Query-Table | Query syslog, execution history, script records |
SN-Execute-Background-Script | Run diagnostic scripts on the instance |
SN-Get-Record | Retrieve specific log or script records |
REST API (ChatGPT/Other)
| Endpoint | Method | Purpose |
|---|---|---|
/api/now/table/syslog | GET | Query system logs |
/api/now/table/sys_script_execution_history | GET | Query script execution history |
/api/now/table/syslog_transaction | GET | Query transaction logs |
Native Tools (Claude Code)
| Tool | Purpose |
|---|---|
Bash | Execute curl commands for REST API |
Read | Read local script files for comparison |
Best Practices
- Always include context: Log function name, record identifier, and operation type
- Use appropriate log levels: Debug for development, Info for production tracing, Error for issues
- Clean up debug code: Remove or disable verbose logging before promoting to production
- Use conditional logging: Wrap debug statements in property checks
- Structured logging: Use consistent format:
[Component] Action - Details - Test in sub-production: Always debug in dev/test before touching production
Troubleshooting
Logs Not Appearing
Symptom: gs.log/gs.info statements not showing in System Logs Cause: Log level filtered or property disabled Solution:
- Check System Properties for
glide.log.level - Ensure
glide.script.log.levelallows your log level - Use
gs.error()which always logs
Script Debugger Not Triggering
Symptom: Breakpoints not hit when script executes Cause: Wrong session, script cached, or condition not met Solution:
- Ensure debugging enabled for YOUR session (not another admin)
- Clear cache: System Diagnostics > Cache Management > Flush Cache
- Verify script condition evaluates to true
Business Rule Not Firing
Symptom: Business rule appears inactive despite being enabled Cause: Condition not met, wrong table, or filter condition Solution:
Tool: SN-Query-Table
Parameters:
table_name: sys_script
query: name=YOUR_BUSINESS_RULE_NAME
fields: name,active,collection,when,order,condition,filter_condition,script
limit: 1
Examples
Example 1: Trace Business Rule Execution
// Add to business rule for debugging
(function executeRule(current, previous) {
var startTime = new Date().getTime();
var brName = 'Validate Incident Priority';
gs.info('[' + brName + '] START - Record: ' + current.number);
try {
// Original business rule logic
if (current.priority == 1 && !current.assignment_group) {
gs.info('[' + brName + '] Setting mandatory assignment group');
gs.addErrorMessage('Critical incidents require an assignment group');
current.setAbortAction(true);
}
} catch (e) {
gs.error('[' + brName + '] ERROR: ' + e.message + '\nStack: ' + e.stack);
}
var duration = new Date().getTime() - startTime;
gs.info('[' + brName + '] END - Duration: ' + duration + 'ms');
})(current, previous);
Example 2: Query Recent Errors
Tool: SN-Query-Table
Parameters:
table_name: syslog
query: level=error^sys_created_onONLast 24 hours@javascript:gs.hoursAgo(24)@javascript:gs.nowDateTime()
fields: sys_created_on,source,message
limit: 100
order_by: sys_created_on
order_by_desc: true
Example 3: Debug Client Script with GlideAjax
// Client Script
function onLoad() {
console.log('[MyClientScript] Form loaded, fetching data...');
var ga = new GlideAjax('MyAjaxProcessor');
ga.addParam('sysparm_name', 'getData');
ga.addParam('sysparm_record_id', g_form.getUniqueValue());
ga.getXMLAnswer(function(response) {
console.log('[MyClientScript] Response received:', response);
if (!response) {
console.error('[MyClientScript] Empty response from server');
return;
}
try {
var data = JSON.parse(response);
console.table(data);
} catch (e) {
console.error('[MyClientScript] Failed to parse response:', e);
}
});
}
Example 4: Background Script for Log Analysis
Tool: SN-Execute-Background-Script
Parameters:
script: |
// Find all errors in last hour with stack traces
var gr = new GlideRecord('syslog');
gr.addQuery('level', 'error');
gr.addQuery('sys_created_on', '>=', gs.hoursAgo(1));
gr.orderByDesc('sys_created_on');
gr.setLimit(20);
gr.query();
var results = [];
while (gr.next()) {
results.push({
time: gr.sys_created_on.getDisplayValue(),
source: gr.source.toString(),
message: gr.message.toString().substring(0, 200)
});
}
gs.info('=== Recent Errors ===\n' + JSON.stringify(results, null, 2));
description: Analyze recent error logs
Related Skills
development/script-includes- Writing reusable server-side scriptsdevelopment/business-rules- Business rule development and best practicesdevelopment/client-scripts- Client-side scripting techniquesadmin/script-execution- System log configuration and management
References
Signals
- GitHub stars
- 37
- Forks
- 13
- Last commit
- Jul 2026
Advanced
- Catalog kind
- skill
- Gateway key
debugging-techniques-happy-technologies-llc- Source
- github.com/happy-technologies-llc/happy-platform-skills