Debug q Code
Configure your environment for interactive debugging, inspect the stack to diagnose runtime errors, and implement programmatic traps for production.
Overview
- Prepare the environment: Enable debug mode
- Trigger errors: Generate an error to see the debugger
- Inspect the stack: Check variable values
- Resolve the suspension: Fix the error or abort
- Programmatic traps: Handle errors in production
- Remote debugging: Capture errors from remote servers
Prepare the environment
Configure your session to handle errors interactively by setting the error mode to Suspend (Mode 1) using \e. This stops execution at the error so you can inspect the state.
Prerequisites
Use v4.0+ (check .z.K) for advanced features like & (frame info) and .Q.sbt.
q)// Check version
q)if[4.0>.z.K;-2 "Warning: KDB-X 4.0+ recommended for full debug functionality"];
q)// Set error mode to Suspend
q)\e 1
Available error modes
KDB-X supports three error modes. The effective default depends on the execution context (see Error trap modes).
| Command | Mode | Behavior | Use Case |
|---|---|---|---|
\e 0 |
Abort | Clears stack and returns error. | IPC / Sync messages (Default override) |
\e 1 |
Suspend | Enters interactive debugger. | Console / Development (Default override) |
\e 2 |
Dump | Prints stack trace and aborts. | Headless / Production |
Trigger and interpret errors
With your environment configured, test your setup by generating a controlled error to see the debugger in action.
q)calculate:{x+10}
q)process:{calculate x}
q)main:{process x}
q)
q)// Trigger a Type Error to enter suspension
q)main `type_error
'type
[3] calculate:{x+10}
^
q))
Visual Guide: Interpreting the suspension
When the debugger suspends, check for these signs:
- Suspension depth: The prompt adds
)(for example,q))). Each)represents one level - Error marker: A caret
^points to the failed primitive - Frame index: Bracketed numbers (for example,
[0]) show the stack frame
Navigate and inspect the stack
Once execution is suspended, use the debugger to inspect the application state and check variable values at the time of the error.
Reference: Debugger commands
Inspection
| Command | Description |
|---|---|
.Q.bt[] |
Print the full backtrace. >> marks the current frame. |
& |
Print local variables in the current frame (v4.0+). |
.z.ex |
Return the failed primitive. |
.z.ey |
Return the arguments passed to the failed function. |
Navigation
| Key | Action |
|---|---|
` |
Move up to an older (parent) frame. |
. |
Move down to a newer (child) frame. |
q))// Inspect the error context
q)).z.ex / View failed primitive
+
q)).z.ey / View arguments
`type_error
10
q)).Q.bt[] / Print backtrace
[3] calculate:{x+10}
^
[2] process:{calculate x}
^
[1] main:{process x}
^
>>[0] main `type_error
^
Resolve the suspension
After identifying the root cause, decide whether to fix the issue to resume execution or to abort the process entirely.
q)):20 / Resume and return 20
q)): / Resume and return generic null (::)
q))\ / Abort execution and clear the stack
Nested debugging
If you are in a nested debug session (for example, q)))), \ pops only one level. Repeat until you reach the root prompt q).
Implement programmatic traps
While interactive debugging is ideal for development, production environments require a different approach. Since you cannot stop execution in production, use .Q.trp and .Q.sbt to log stack traces automatically.
Handler arguments
err: The error stringbt: The backtrace object
safeRun:{[f;x]
.Q.trp[f;x;{[err;bt]
-2"Captured Runtime Error: ",err;
-2"Stack Trace:";
-2 .Q.sbt bt;}]};
// Execute with trap
safeRun[{x+`a};1]
Captured Runtime Error: type
Stack Trace:
[3] {x+`a}
^
[2] (.Q.trp)
[1] safeRun:{[f;x].Q.trp[f;x;{[err;bt] -2"Captured Runtime Error: ",err;-2"Stack Trace:";-2 .Q.sbt bt;}]}
^
[0] safeRun[{x+`a};1]
^
Parse errors
Errors thrown by parse also appear in .Q.trp with location information, essentially treating syntax errors in dynamic code as runtime errors.
Configure remote debugging
You may need to debug across network boundaries. To capture remote stack traces, wrap the request handler .z.pg. This returns the backtrace to the client for diagnosis.
Server setup
Start the server process (for example, on port 5001) and define the request handler to capture stack traces.
/ Start server on port 5001
\p 5001
/ Define .z.pg to return (0;result) or (1;backtrace)
.z.pg:{[x]
.Q.trp[
{(0;value x)}; / Try: Execute request
x; / Arg: Incoming query
{[err;bt] (1;"Remote Error: ",err,"\n",.Q.sbt bt)} / Catch: Return (1; Error Log)
]
}
/ Define a function that will fail
f:{{x*y}[x;3#x]}
Protocol details
This example uses a simple list protocol to distinguish success from failure:
- Success:
(0; result) - Failure:
(1; backtrace)
The client checks the first element to determine how to handle the response.
Client session
Connect to the server and handle the response protocol.
q)// Connect to remote
q)h:hopen 5001
q)// Execute a query that signals an error
q)r:h"f `a"
q)// The first element indicates failure (1)
q)r 0
1
q)// The second element contains the formatted backtrace
Remote Error: type
[5] f@:{x*y}
^
[4] f:{{x*y}[x;3#x]}
^
[3] f `a
^
[2] .z.pg@:{(0;value x)}
^
[1] (.Q.trp)
[0] .z.pg:{[x].Q.trp[{(0;value x)};x;{[err;bt] (1;"Remote Error: ",err,"\n",.Q.sbt bt)}]}
^
Client-side handling
Check the response format on the client. If the first element is 1, print the backtrace from the second element.