agentleFS
Happy-Technologies-LLCHappy-Technologies-LLC/happy-platform-skills/skills/development/debugging-techniques/SKILL.md

debugging-techniques

Skill41 starsChanged 6 days agoApache-2.0View on GitHub

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

We split this skill into the rules it gives an agent

19 rules. About 0 are common, 15 are distinctive, and 4 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈15

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 4

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Use Watch panel to monitor variables

    line 167
  2. Distinctive:

    Use Scope panel to inspect local/closure variables

    line 168
  3. Distinctive:

    Look for calls to:

    line 191
  4. Distinctive:

    Check ACL logs: System Logs > Security

    line 358
  5. Distinctive:

    Check System Logs for stack trace

    line 373
  6. Distinctive:

    Use Script Debugger to step through

    line 374
  7. Distinctive:

    Add GlideAggregate for counting instead of looping

    line 381
  8. Distinctive:

    Use setLimit() to restrict result sets

    line 382
  9. Distinctive:

    Check for recursive business rules

    line 389
  10. Distinctive:

    Add condition to prevent re-entry:

    line 390
  11. Distinctive:

    Use GlideAggregate for counts

    line 401
  12. Distinctive:

    Clean up debug code: Remove or disable verbose logging before promoting to production

    line 433
  13. Very specific:

    Structured logging: Use consistent format: [Component] Action - Details

    line 435
  14. Distinctive:

    Test in sub-production: Always debug in dev/test before touching production

    line 436
  15. Very specific:

    Check System Properties for glide.log.level

    line 445
  16. Very specific:

    Ensure glide.script.log.level allows your log level

    line 446
  17. Very specific:

    Use gs.error() which always logs

    line 447
  18. Distinctive:

    Ensure debugging enabled for YOUR session (not another admin)

    line 454
  19. Distinctive:

    Verify script condition evaluates to true

    line 456

≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

ServiceNow Debugging Techniques

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

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.