OBLYTECH Logo
OBLYTECH Logo
ServiceNow Script Debugger Explained
Home / Guides, Services and Solutions / Concepts Explained / ServiceNow Script Debugger Explained

ServiceNow Script Debugger Explained

Definition and Access

The Script Debugger is a built-in tool in ServiceNow that lets you step through server-side scripts (business rules, script actions, scheduled jobs) line by line, inspecting variable values, setting breakpoints, and understanding how your code executes. Instead of guessing why a script fails or produces unexpected results, you run it with the debugger attached and watch it run in real time, tracing execution flow and data transformations.

Access the debugger via the admin interface: Admin > System Logs > Script Debugger, or by enabling debug mode in specific contexts (business rule, script action). Once enabled, the next execution of your script pauses at breakpoints and waits for your input.

Setting Breakpoints and Stepping Through Code

A breakpoint is a marked line where execution pauses. You set breakpoints by clicking the line number in the script editor or using `debugger;` in code. When the script reaches a breakpoint, the debugger pauses and displays the current state: variable values, stack trace, and the next line to execute.

From a breakpoint, you can: Step Over (execute the next line), Step Into (enter a function), Step Out (run to the end of the current function), or Continue (run to the next breakpoint). This control lets you follow code execution and spot where logic diverges from what you expected.

Inspecting Variables and Expressions

The debugger displays all local and global variables available at the breakpoint. You can hover over variables to see their values, or type expressions into the debug console to evaluate them: `gr.priority` shows the value of a Glide Record’s priority field. `Math.round(total / count)` calculates an expression.

Some variables are objects (like Glide Records). The debugger expands them to show nested properties: click the arrow next to `gr` to see `gr.short_description`, `gr.priority`, etc. This visibility into object state is invaluable for debugging complex scripts and understanding data transformations.

Common Debugging Scenarios

A business rule is not executing: set a breakpoint at the first line and trigger the condition. If the breakpoint does not hit, the condition is false or the rule is disabled. A script produces wrong output: set breakpoints at key calculations and inspect intermediate values to find where the logic diverges. A Glide Record query returns no results: step through the query setup and inspect filter values to see if they are what you expect.

Performance debugging: if a script is slow, set breakpoints around expensive operations (database queries, loops) and measure how long each takes using the debugger’s timing features. This often reveals that a loop is running thousands of times when it should run only once.

Remote Debugging and Production Caveats

The Script Debugger works in development and test environments. Using it in production is risky: while debugging, code execution pauses indefinitely, blocking the process. Other users or automations waiting for that record may time out. Only use production debugging for urgent troubleshooting, and only when you can guarantee no other users are affected by the delay.

Some organisations implement a scheduled script that attaches a debugger to specific code, logs output to a table, and detaches automatically. This gives you debugging insight without blocking end users or business processes.

Alternative: Logging and GlideSystem.log()

Instead of interactive debugging (which pauses code), many developers use logging: add `gs.log(‘variable=’ + someVar, ‘MyScript’);` throughout the script, then review logs after execution. Logging is safer for production debugging but provides less immediate insight than step-by-step execution.

When stepping through code, pay attention to variable scope: a variable defined inside a function is not visible outside it. The debugger shows scope boundaries clearly. Understanding scope is essential for troubleshooting data loss where a calculation happens but the result is not available where expected.

Pick the cheapest way to see what the script did

A developer who has a misbehaving server script usually reaches for the debugger first, because stepping through code feels like the most direct route to the answer. It is often not the cheapest. Stepping through a script is slow when the fault depends on data that arrived an hour earlier, on an event that fired from another table, or on a role the developer does not hold. A better habit is to ask what evidence would settle the question, and then choose the lightest tool that can produce it: a log line already present in the System Log, a background script that reads the record, a replay of the triggering update in a copy of the instance, or an interactive breakpoint as the last step.

That ordering matters because each tool has a different cost in time, risk and how much it disturbs other users. A breakpoint in a transaction that another person is waiting on is far more expensive than a read-only query that returns the same field values.

Matching the symptom to the first check

The table below gives a starting point for the most common server script problems. The first check is the one that rules out the most explanations for the least effort.

Symptom First check Tool to use next What to avoid
Script never runs Whether the trigger condition is met on the exact record, including its current values A background script that evaluates the same condition and prints the result Stepping through a body that never executes
Runs, but the field value is wrong Which script or business rule last wrote the field, and in what order rules ran Log lines at each write, with the record number and the value written Changing the rule before knowing which one caused the write
Works for an administrator, fails for a user The roles and access rules that apply to the user, not the admin Reproduce by impersonating a representative user in a non-production copy Adding elevated access to make the failure go away
Slow under load Whether a GlideRecord query runs inside a loop or on every row of a large result Timing logs around each query, then a comparison with a smaller data set A breakpoint, which adds delay to the very behavior under test
Intermittent failure Whether it correlates with a scheduled job, an import or an integration call Structured log lines that include the source of the triggering event Assuming randomness before the timing has been checked

Reproducing the failure without disturbing production

The fastest debugging session is one that happens on a copy of the data, with the same script version and the same user role. Many teams skip this step and debug live, which is how a developer can end up pausing a process that many people depend on. The procedure below keeps the investigation contained.

  1. Record the exact script or rule version, the table, the record identifier, the user or process that triggered it, and the time it happened.
  2. Confirm the record’s values as they were at that moment, using the history of the record rather than its current state, since later edits can hide the cause.
  3. Recreate the record in a non-production copy with the same field values, and run the trigger under a user with the same roles.
  4. Add temporary log lines at the points where values change, and remove them before the change is promoted.
  5. Only if the log lines do not explain the fault, attach the debugger in the non-production copy and step through the smallest section that still reproduces it.
  6. Note the cause and the remedy in the change record, so a later developer begins from the finding.

Step two is the one most often skipped. A record that has since been edited by a later update will show values that never existed when the script ran, and a fix built on those values will not hold.

What a transaction boundary does to what you see

Server scripts run inside a transaction. Changes made by a script are not visible to other users until the transaction completes, and an error part way through can roll back work that the developer saw succeed on screen. That behavior makes some debugging sessions misleading. A value that appears correct at a breakpoint may never be committed, and a log line written before the failure may describe a change that was undone. When investigating a write problem, check whether the failing code sits before or after a point where the transaction could be abandoned, and treat the log as a record of attempts rather than of outcomes.

Asynchronous work adds another layer. An event queued by one script may run later, under a different context and with fresh values. A breakpoint placed in the handler will only be reached when that handler runs, which can be long after the code that queued it has finished. The guidance on automation exception handling covers defining a path for containment, explanation and ownership when automated work fails.

When not to attach a debugger at all

Some situations make an interactive breakpoint the wrong choice even when it would work. A breakpoint pauses execution, and any process waiting on the paused code waits too. Production is the obvious case, but a shared test instance used by a release team can be just as sensitive, and a breakpoint left in place can block a scheduled job that runs overnight. A breakpoint is also a poor choice for a performance question, because the pause changes the timing being measured.

For behavior that should stay correct over time, an automated test is a better investment than repeated debugging. Once the cause is known, capture the failing case as a test so that a later change cannot reintroduce it, and keep the relevant automated testing governance in view when deciding where that test belongs.

Questions developers ask about script debugging

Why does the debugger skip my breakpoint on a script that clearly runs?

A common reason is that the code runs in a different context from the one you attached to, such as an event handler, a scheduled job or a background execution started by another user. Confirm which execution path actually reached the line, and attach to that path, rather than assuming the script is the same everywhere it is called.

Is a log line a substitute for stepping through?

For most write and condition problems, a few well-placed log lines answer the question faster and with less risk. Stepping through is most useful when the question is about control flow inside a loop or a complex condition that the log cannot expose without a great deal of output.

How should temporary debugging code be handled?

Mark every temporary line with a comment that names the ticket and the date it was added, and check for those markers before the change set is submitted. Leaving diagnostic output in a promoted script can be a source of noise in the system log for months afterwards.

Does a fix need to be tested with the same user who reported the problem?

Ideally yes, or a user with the same roles and the same access rules. Testing with an administrator confirms the logic works but says nothing about whether the user can see the data the logic depends on.

If scripts in your instance are regularly paused for investigation, a review of how they are built and logged, following the same ground as the business rules governance and performance guide, can reduce how often that happens.

Frequently asked questions

Can we set a conditional breakpoint that only pauses if a variable meets a certain value?

The script debugger does not support conditional breakpoints directly, but you can write code that conditionally hits a breakpoint: `if (total > 100) { debugger; }` pauses only when total exceeds 100. Alternatively, add `if (condition) gs.log('debug checkpoint', 'MyScript');` and review logs.

What if we set a breakpoint and forget to remove it before deploying?

Breakpoints are part of the script text only if you use `debugger;` statements. Breakpoints set via the UI are not stored in the script. However, leaving a `debugger;` statement in code will cause that script to pause whenever it executes, potentially blocking production. Always search for and remove `debugger;` before deploying.

How do we debug a scheduled job or flow action that runs asynchronously?

Asynchronous code runs in the background and does not attach to a user session, so interactive debugging is not possible. Use logging extensively: add gs.log() statements before and after key operations, then review the job's execution logs. Some developers write asynchronous code to update a debug table so they can review state after execution.

Talk to Oblytech

Planning, running or fixing a ServiceNow programme? Tell us where you are and we will suggest a sensible next step.

Contact us