ServiceNow Debugging Techniques

SkillDev tools

Comprehensive guide to debugging ServiceNow server-side and client-side code

Available today. Use it from your connected AI after setup.

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: admin or script_write for 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.

FunctionLog LevelUse Case
gs.log(message, source)DebugDevelopment/testing - legacy, prefer gs.debug
gs.debug(message)DebugDetailed troubleshooting (requires debug enabled)
gs.info(message)InfoInformational messages for normal operations
gs.warn(message)WarningPotential issues that don't stop execution
gs.error(message)ErrorErrors 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:

  1. Navigate to System Diagnostics > Script Debugger
  2. Click Enable Debugging for your session
  3. Set breakpoints in scripts using the debugger UI
  4. Trigger the script (e.g., update a record)
  5. 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:

ModulePurposeEnable Path
Session DebugAll session debuggingSystem Diagnostics > Session Debug > All
Business RulesLog BR executionSystem Diagnostics > Session Debug > Business Rules
SQLLog database queriesSystem Diagnostics > Session Debug > SQL
SecurityACL debuggingSystem Diagnostics > Session Debug > Security
Client ScriptsLog client script dataSystem 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

MethodPurpose
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:

  1. Open DevTools (F12 or Cmd+Option+I)
  2. Navigate to Sources tab
  3. Find client scripts under scripts.do?sysparm_type= or in the page source
  4. Set breakpoints by clicking line numbers
  5. Use Watch panel to monitor variables
  6. 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:

  1. Open DevTools > Network tab
  2. Filter by XHR/Fetch
  3. Look for calls to:
    • xmlhttp.do - GlideAjax calls
    • api/now/ - REST API calls
    • sysparm_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):

  1. before rules (order ascending) - Execute before database write
  2. after rules (order ascending) - Execute after database write
  3. 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:

  1. Open the flow in Flow Designer
  2. Click More Actions (three dots) > Debug
  3. Trigger the flow
  4. 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:

  1. Enable Session Debug > Security
  2. Check ACL logs: System Logs > Security
  3. 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:

  1. Check System Logs for stack trace
  2. Use Script Debugger to step through
  3. 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)

ToolPurpose
SN-Query-TableQuery syslog, execution history, script records
SN-Execute-Background-ScriptRun diagnostic scripts on the instance
SN-Get-RecordRetrieve specific log or script records

REST API (ChatGPT/Other)

EndpointMethodPurpose
/api/now/table/syslogGETQuery system logs
/api/now/table/sys_script_execution_historyGETQuery script execution history
/api/now/table/syslog_transactionGETQuery transaction logs

Native Tools (Claude Code)

ToolPurpose
BashExecute curl commands for REST API
ReadRead 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:

  1. Check System Properties for glide.log.level
  2. Ensure glide.script.log.level allows your log level
  3. 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:

  1. Ensure debugging enabled for YOUR session (not another admin)
  2. Clear cache: System Diagnostics > Cache Management > Flush Cache
  3. 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 scripts
  • development/business-rules - Business rule development and best practices
  • development/client-scripts - Client-side scripting techniques
  • admin/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