What It Is
A breakpoint is a debugging marker that instructs the ServiceNow Script Debugger to pause script execution at a specific line of code, allowing you to inspect the current state of variables, examine the call stack, and step through your code line by line. When a breakpoint is hit, the server suspends the executing thread and establishes a debugging session that connects your browser-based debugger interface to the server-side JavaScript execution context. This mechanism solves the fundamental problem of server-side script visibility — without breakpoints, debugging complex Business Rules, Script Includes, or Workflow activities becomes a frustrating exercise in gs.log() statements and guesswork.
Breakpoints live within the Script Debugger application, which is part of ServiceNow's core platform debugging infrastructure built on the Rhino JavaScript engine. The debugger hooks into the server-side script execution pipeline at the Virtual Machine level, intercepting script execution before each line runs and checking for active breakpoint conditions. This operates independently of the client-side debugging tools you might use for Client Scripts or UI Actions — breakpoints only function for server-side code execution including Business Rules, Script Includes, Processors, Transform Maps, and any other server-side JavaScript contexts.
The breakpoint mechanism integrates directly with ServiceNow's script execution engine, which means it can capture the exact moment when your code interacts with the ServiceNow data model through GlideRecord operations, system properties, or custom Script Include methods. When a breakpoint triggers, you gain access to the complete execution context including local variables, function parameters, the current record object, and any other objects in scope at that line. The debugger maintains this state until you either continue execution, step to the next line, or terminate the debugging session, making it possible to examine complex object hierarchies and understand exactly how your script affects the underlying database records.
You cannot effectively debug complex server-side integration scenarios without breakpoints — particularly when dealing with multi-step Business Rules that modify records, Script Includes that perform complex calculations, or Transform Maps that process incoming data feeds. When a Business Rule isn't updating fields as expected, when a Script Include returns unexpected values, or when an integration processor fails silently, breakpoints become the only reliable method to observe the actual execution flow and variable states. The alternative approaches of adding logging statements or using gs.print() in Background Scripts provide limited visibility and require code modifications that must be removed afterward.
Developers primarily manage breakpoints, though system administrators with the debug role can access the Script Debugger interface. The debugging session is user-specific and instance-specific — breakpoints you set in your development environment won't affect other users or other instances. Platform owners typically restrict debugger access in production environments since active debugging sessions can impact performance and expose sensitive data, though the debugger provides essential capabilities for troubleshooting critical production issues when used judiciously.
Recent ServiceNow releases have enhanced breakpoint functionality with improved variable inspection and better support for scoped applications. Vancouver introduced more reliable breakpoint handling in Script Includes within scoped applications, addressing previous issues where breakpoints in private Script Includes wouldn't always trigger correctly. Xanadu improved the debugger's ability to handle asynchronous script execution and provided better integration with App Engine Studio, making it easier to debug custom applications built through low-code development tools. The core breakpoint mechanism remains consistent across releases, but these improvements have made debugging more reliable, particularly in complex multi-scope environments.
Where to Find and Configure It
Access the Script Debugger through System Definition > Script Debugger where you'll find the main debugging interface with tabs for Scripts, Breakpoints, and Variables. The Scripts tab displays all server-side scripts available for debugging, the Breakpoints tab shows your active breakpoints with their conditions and hit counts, and the Variables tab becomes populated with local and global variables when a breakpoint is hit during execution.
Within ServiceNow Studio, access breakpoints by opening any server-side script (Business Rule, Script Include, or Processor) and clicking in the left margin next to the line numbers where you want to pause execution. Studio automatically syncs these breakpoints with the Script Debugger, providing a more integrated development experience. In App Engine Studio, breakpoints work similarly when editing custom scripts within your application's Business Rules or Script Includes, though you'll need to switch to the full Script Debugger for advanced breakpoint management and variable inspection.
View active debugging sessions and breakpoint hits in System Logs > Script Execution History where each debugging session appears as a separate entry with execution time, user context, and any logged output. For scoped applications, breakpoints function identically to global scope but only trigger when executing scripts within that specific application scope — breakpoints set in a scoped Business Rule won't trigger when similar logic runs in a different scope's Business Rule, providing clean separation between application debugging contexts.
How It Works Step by Step
When you set a breakpoint, ServiceNow registers that line number and script identifier with the Rhino JavaScript engine's debugging interface. The platform maintains a registry of active breakpoints tied to your user session, checking this registry before executing each line of server-side JavaScript code. This happens at the virtual machine level, meaning the performance impact is minimal when no breakpoints are active, but becomes more significant when breakpoints are set since every script execution must check against the breakpoint registry.
Once a breakpoint is hit, the JavaScript execution thread suspends and ServiceNow establishes a debugging session that bridges the server-side execution context with your browser-based debugger interface. The platform serializes the current execution state including variable values, call stack information, and object references, then waits for debugging commands from your browser session. This suspended state can persist indefinitely until you issue a continue, step, or terminate command, though ServiceNow will eventually timeout long-running debugging sessions to prevent resource exhaustion.
Enjoying this? Get one deep-dive per week.
Join 1,000+ ServiceNow pros — scripts, GlideRecord patterns, Flow Designer techniques, and career moves. Free.
The Execution Order
- User action triggers server-side script execution (form submission, scheduled job, integration call, etc.)
- ServiceNow identifies the relevant scripts to execute and loads them into the Rhino JavaScript engine
- Before executing each line, the engine checks the breakpoint registry for matching script and line number combinations
- When a breakpoint match is found, execution suspends and ServiceNow captures the current execution context including variable states and call stack
- The platform establishes a debugging session and notifies your browser-based debugger interface that a breakpoint has been hit
- Your debugger interface loads the script source, highlights the current line, and populates variable inspection panels with current values
- You can now inspect variables, modify values, evaluate expressions, or issue step/continue commands to control execution flow
- When you continue or step, ServiceNow resumes script execution from the breakpoint line, maintaining any variable changes you made during debugging
// Common Business Rule pattern where breakpoints are essential
(function executeRule(current, previous) {
// Set breakpoint here to inspect initial record state
var assignmentGroup = current.assignment_group.toString();
var priority = current.priority.getValue();
if (assignmentGroup && priority == '1') {
// Set breakpoint to examine Script Include parameters
var notifier = new IncidentNotificationUtils();
var result = notifier.sendUrgentAlert(current, assignmentGroup);
// Set breakpoint to verify notification results
if (result.success) {
current.u_notification_sent = true;
current.u_notification_time = new GlideDateTime();
} else {
gs.error('Notification failed: ' + result.message);
}
}
})(current, previous);Real-World Scenarios
Debugging Complex Business Rule Interactions
Multiple Business Rules firing on the same table are causing unexpected field updates, and you need to identify which rule is modifying specific values and in what order. The rules involve complex conditional logic that makes it difficult to predict execution flow through code review alone.
Open the Script Debugger and navigate to each Business Rule that might be affecting your target record. Set breakpoints at the beginning of each rule's execution and at key decision points where field modifications occur. Create or modify a test record that triggers the problematic behavior, then step through each breakpoint to observe the field values at each stage. Use the Variables panel to compare current and previous record states to identify exactly when and how each field changes.
Pay attention to the execution order shown in your debugging session, as Business Rules fire based on their Order value and timing (before/after/async). Watch for rules that modify fields which then trigger additional Business Rules, creating cascading effects that might not be obvious from the rule configurations alone. Remember to remove or disable breakpoints after debugging to avoid impacting other users working with the same records.
Troubleshooting Script Include Return Values
A custom Script Include that performs calculations or data transformations is returning incorrect results in production, but the logic appears sound when reviewed statically. You need to examine the actual data being processed and the intermediate calculation steps to identify where the logic fails.
Set breakpoints at the Script Include's entry point to inspect the parameters being passed in, then add additional breakpoints at key calculation steps and before each return statement. Use a Background Script or the calling code that reproduces the issue to trigger the Script Include execution. Step through each calculation, examining variable values in the Variables panel to identify where the actual values diverge from expected values. Use the Console tab to evaluate expressions and test alternative calculations in real-time.
Script Include breakpoints in production should be used sparingly since they can affect all users calling that Script Include. Consider copying the Script Include to a test version for debugging when possible.
Analyzing Transform Map Data Processing
An import process using Transform Maps is failing to properly map certain data fields, or the transformation scripts are producing unexpected results for specific data patterns. Standard Transform Map testing doesn't provide sufficient visibility into the transformation logic execution.
Navigate to your Transform Map and open the transformation scripts where issues are occurring. Set breakpoints within the onBefore, onAfter, or field mapping scripts to examine the source record data and target record being created. Run your import or use the Transform Map test functionality to trigger the transformation with problematic data. Step through the mapping logic to observe how source field values are interpreted and transformed, paying particular attention to data type conversions and field validation logic.
Focus on examining the source data structure and any preprocessing that occurs before field mapping, as unexpected data formats or encoding issues often cause transformation failures that aren't obvious from the Transform Map configuration. Use the debugger to test different approaches to data parsing or validation within the transformation scripts. Be aware that Transform Map debugging can be resource-intensive if processing large data sets, so test with smaller data samples when possible.
The Classic Mistake
Setting breakpoints in Business Rules that fire on table operations during Script Debugger sessions without understanding the session scope will cause infinite loops or missed breakpoints.
// BAD: Setting breakpoint in Business Rule during active debugging
(function executeRule(current, previous) {
// Breakpoint set here while debugging another script
var gr = new GlideRecord('incident');
gr.addQuery('state', 1);
gr.query();
while (gr.next()) {
// This will trigger more Business Rules
gr.setValue('priority', '1');
gr.update(); // Creates cascade of rule executions
}
gs.log('Updated ' + gr.getRowCount() + ' incidents');
})(current, previous);This fails because the Script Debugger session remains active across all server-side script executions within the same user session, including Business Rules triggered by GlideRecord operations. When you set a breakpoint in a Business Rule and then perform operations that trigger that same rule, ServiceNow creates a recursive debugging scenario where each gr.update() call fires the Business Rule again, hitting the same breakpoint. The user sees the debugger interface hanging or repeatedly pausing on the same line, while ServiceNow is actually processing dozens or hundreds of rule executions in the background. This behavior is non-obvious because the Script Debugger doesn't clearly indicate when you're debugging nested executions versus the original script flow.
// GOOD: Use specific conditions or separate debugging sessions
(function executeRule(current, previous) {
// Only break for specific records during debugging
if (current.number == 'INC0010001' && gs.getProperty('glide.script.debug.enabled') == 'true') {
// Breakpoint here - controlled scope
gs.log('Debug breakpoint for specific incident: ' + current.number);
}
// Use direct updates to avoid rule cascades during debugging
gs.executeNow('var gr = new GlideRecord("incident"); gr.get("' + current.sys_id + '"); gr.setValue("priority", "1"); gr.setWorkflow(false); gr.autoSysFields(false); gr.update();');
})(current, previous);Never set breakpoints in Business Rules that could be triggered by your debugging session's data operations. Always use conditional breakpoints tied to specific record identifiers, or debug Business Rules in isolation using Background Scripts with controlled data.
When to Use This vs Alternatives
Use breakpoints when you need to inspect variable state and execution flow in complex server-side scripts where gs.log() statements would be insufficient or too numerous to be practical. Breakpoints shine when debugging multi-step workflows, complex Business Rules with conditional logic, or Script Includes with intricate object manipulations where you need to examine object properties at specific execution points.
When Breakpoints Are the Right Choice
Choose breakpoints over logging when debugging Transform Maps, complex Workflow activities, or Script Includes where object state changes rapidly and you need to examine intermediate values. Logging falls short here because you'd need dozens of gs.log() statements, and the logs become unreadable. Breakpoints let you inspect the complete object hierarchy and step through conditional branches in real-time, which is impossible with static logging.
When to Use Logging Instead
Use gs.log() statements instead of breakpoints for production troubleshooting, performance analysis, or when debugging scripts that execute frequently (like Business Rules on high-volume tables). Breakpoints require active user sessions and will timeout, making them useless for intermittent issues that occur hours apart. For scheduled jobs, Background Scripts, or any script where you need historical debugging data, logging is the only viable option.
When You Need Both Together
Combine breakpoints with strategic logging when debugging integration scripts or complex approval workflows where you need real-time inspection during development but also want permanent logging for production monitoring. Use breakpoints to understand the logic flow and identify the key decision points, then add targeted gs.log() statements at those critical points before removing the breakpoints for production deployment.
Platform Interactions & Side Effects
- Script Debugger sessions write to
sys_script_sessiontable and maintain state in the user's HTTP session, causing memory consumption that persists until session timeout - Active breakpoints extend Business Rule execution time, potentially causing workflow timeouts and triggering
glide.script.timeoutsystem property violations - Breakpoints in Transform Maps prevent Import Set processing from completing, leaving records in
pendingstate until the debugging session ends - Debugging sessions bypass normal ACL evaluation for script inspection, allowing admins to view field values they normally couldn't access
- Update Set capture continues during breakpoint sessions, recording all debugging-related script modifications with
sys_update_xml.actionentries - Email notifications triggered by scripts pause at breakpoints, delaying delivery until script execution completes
- Scheduled Jobs with breakpoints will appear as
Runningindefinitely insysauto_scriptuntil the debugging session times out - Application scoping restrictions don't apply during debugging, allowing cross-scope variable inspection that normal script execution would block
- Performance Analytics collection pauses during breakpoint sessions, creating data gaps in metrics that depend on real-time script execution
- Database transaction isolation can break during long debugging sessions, causing unexpected rollbacks when breakpoints span multiple GlideRecord operations
Debugging and Troubleshooting
The most common failure symptoms include breakpoints that never trigger, the Script Debugger interface showing No active sessions when you expect them to hit, or debugging sessions that hang indefinitely without advancing to the next line. Users typically see slow response times, scripts that appear to execute but show no debugging interface, or error messages about session timeouts. These symptoms often indicate session scope issues, incorrect breakpoint placement, or conflicts with other system processes.
When breakpoints aren't working, check System Logs > All for Script Debugger entries, examine the sys_script_session table for active debugging records, and verify the glide.script.debug.enabled system property is set to true. Look for error messages containing Script timeout, Debugging session expired, or No script session found in the application logs, which indicate session management problems.
Debug output in the Script Debugger console often shows incomplete variable information or [object Object] instead of actual values, which usually means you're trying to inspect complex objects that exceed the debugger's serialization limits. The Node Log entries will show Debugger attached and Debugger detached messages when sessions start and end successfully, so missing these entries indicates the debugger never properly initialized.
Diagnostic Checklist:
- Verify
glide.script.debug.enabled=trueandglide.script.debug.timeoutis set to appropriate value (default 300 seconds) - Check for active debugging sessions in
sys_script_sessiontable and clear stale entries - Confirm breakpoints are set in scripts that will actually execute in your current context (not dead code branches)
- Test with a simple Background Script breakpoint first to validate debugger functionality before complex scenarios
- Review browser console for JavaScript errors that might prevent the debugger interface from loading
- Verify you have
adminrole or appropriate debugging permissions for the script type you're testing - Clear browser cache and retry if the Script Debugger interface appears but doesn't respond to controls
Quick Reference
- Debugging sessions automatically timeout after 300 seconds (configurable via
glide.script.debug.timeout), abandoning breakpoints and resuming normal execution - Only one debugging session per user is supported; starting a new session automatically terminates the previous one
- Breakpoints in client-side scripts (Client Scripts, UI Policies) are not supported; only server-side JavaScript can be debugged
- Variable inspection is limited to 1MB of serialized data per object; larger objects show as
[Object too large]in the debugger - Breakpoints persist across browser refreshes but are tied to the specific user session and server node
- Maximum of 50 breakpoints can be set simultaneously across all scripts in a single debugging session
- Script execution during debugging doesn't count against
glide.script.timeoutlimits while paused at breakpoints - Scoped applications can only debug their own scripts unless debugging from the global scope with elevated permissions
- Database connections remain open during debugging sessions, potentially exhausting the connection pool if multiple users debug simultaneously
- Breakpoints cannot be set in encrypted scripts, protected system scripts, or any script marked as
sys_protected=true