Skip to content

Debugging

q)) extra right parens mark suspended execution/s 'myerror Signal error, cut back stack :r exit suspended function with r as result \ abort execution and exit debugger .Q.bt dump backtrace & current frame information .Q.trp extends Trap to collect backtrace -e \e error-trap mode

Errors

Uncaught errors are printed as follows (without the comments). Since V3.5.

q)2+"hi"
'type           / error string
  [0]  2+"hi"   / stack frame index and source code
        ^       / caret indicates the primitive that failed

This will be augmented with file:line and function name, if such information is available.

q)myfun"hi"    / myfun defined in test.q and loaded with \l
'type
  [1]  /kdb+3.5/test.q:5: myfun:{2+x} / note the full path name
                                  ^

Nested anonymous lambdas will inherit their enclosing function's name with the @ suffix.

q)f0:{{("hi";x+y)}[x*2;"there"]}
q)f0[2]
'type
  [2]  f0@:{("hi";x+y)}
                   ^
q)\

A name error (global used as local) bytecode compiler error has location info.

q){a::1;a:1}
'a
  [0]  {a::1;a:1}
             ^

Debugger

Usually when an error happens inside a lambda the execution is suspended and you enter the debugger, as indicated by the additional ) following the normal q) prompt.

q)f:{g[x;2#y]}
q)g:{a:x*2;a+y}
q)f[3;"hello"]
'type
  [2]  g:{a:x*2;a+y}
                 ^
q))

The debug prompt allows operating on values defined in the local scope.

q))a*4
24

You can use ` and . freely to navigate up and down the stack.

q))` / up
  [1]  f:{g[x;2#y]}
          ^
q))`
  [0]  f[3;"hello"]
       ^
q)). / down
  [1]  f:{g[x;2#y]}
         ^
q))

In a debugger session, .z.ex and .z.ey are set to the failed primitive and its argument list.

q)).z.ex
+
q)).z.ey
6
"he"

Signal

'err will signal err from the deepest frame available, destroying it.

q))'myerror
'myerror
  [1]  f:{g[x;2#y]}
          ^
q))

Resume

When execution is suspended, :e resumes with e as the result of the failed operation. e defaults to null ::.

q)read0`:test.q
"/ test script"
"a:b:0"
"func:{1+x}"
"a:func`a"
"b:1"
q)\l test.q
'type
  [3]  <full path to file>/test.q:3: func:{1+x}
                                            ^
q)):42 / result of 1+x
q)a
42
q)b
1

Note that resume does not return from enclosing function

q){0N!"x+1 is ",string x+1;x}`asd
'type
  [1]  {0N!"x+1 is ",string x+1;x}
                             ^
q)):17
"x+1 is 17"
`asd

Abort

Use \ to exit the debugger and abort execution.

q))\
q)

Debuggers may nest if an expression entered into a debug prompt signals an error. Nesting level is indicated by appending further parentheses to the q)) prompt. Each \ exits a single debug level.

q)){x+y}[a;y]
'type
  [5]  {x+y}
         ^
q)))x
6
q)))\          / exit the inner debugger
q))\           / exit the outer debugger
q)

Stack frames

Backtrace

.Q.bt[] will dump the backtrace to stdout at any point during execution or debug. It will highlight the curent stack frame with >>. (Since V4.0 2020.03.17.)

q)g:{a:x*2;a+y}
q)f:{{.Q.bt[];x*2}x+1}
q)f 4
  [2]  f@:{.Q.bt[];x*2}
           ^
  [1]  f:{{.Q.bt[];x*2}x+1}
          ^
  [0]  f 4
       ^
10
q)g[3;"hello"]
'type
  [1]  g:{a:x*2;a+y}
                 ^
q)).Q.bt[]
>>[1]  g:{a:x*2;a+y}
                 ^
  [0]  g[3;"hello"]
       ^

The debugger itself occupies a stack frame, but its source is hidden.

Where

Debugger command & displays current frame information. (Since V4.0 2020.03.17.)

q))&
'type
  [1]  g:{a:x*2;a+y}
                 ^

Context

The debugger restores the original namespace and language (q or k) setting for each frame.

View calculations and system commands, including \l, correspond to individual debug stack frames.

  .d1 ).Q.bt`
 >>[3]  t0.k:8: va::-a
                     ^
   [2]  t1.q:8: vb::va*3
                    ^
   [1]  t1.q:7: vc::vb+2
                    ^
   [0]  2+vc
          ^

Trap

.Q.trp[f;x;g] extends trap (@[f;x;g]) to collect backtrace. Along with the error string, g gets called with the backtrace object as a second argument. You can format it with .Q.sbt to make it legible.

q)f:{`hello+x}
q)           / print the formatted backtrace and error string to stderr
q).Q.trp[f;2;{2@"error: ",x,"\nbacktrace:\n",.Q.sbt y;-1}]
error: type
backtrace:
  [2]  f:{`hello+x}
                ^
  [1]  (.Q.trp)

  [0]  .Q.trp[f;2;{2@"error: ",x,"\nbacktrace:\n",.Q.sbt y;-1}]
       ^
-1
q)

.Q.trp can be used for remote debugging.

q)h:hopen`::5001   / f is defined on the remote
q)h"f `a"           
'type              / q's ipc protocol can only get the error string back
  [0]  h"f `a"
       ^
q)                 / a made up protocol: (0;result) or (1;backtrace string)
q)h".z.pg:{.Q.trp[(0;)@value@;x;{(1;.Q.sbt y)}]}"
q)h"f 3"
0                  / result
,9 9 9             
q)h"f `a"
1                  / failure
"  [4]  f@:{x*y}\n            ^\n  [3..
q)1@(h"f `a")1;    / output the backtrace string to stdout
  [4]  f@:{x*y}
            ^
  [3]  f:{{x*y}[x;3#x]}
          ^
  [2]  f `a
       ^
  [1]  (.Q.trp)

  [0]  .z.pg:{.Q.trp[(0;)@enlist value@;x;{(1;.Q.sbt y)}]}
              ^

Errors thrown by parse show up in .Q.trp with location information.

q).Q.trp[parse;"2+2;+2";{1@.Q.sbt 2#y}];
  [3]  2+2;+2
           ^
  [2]  (.q.parse) 

Error trap modes

At any point during execution, the behavior of Signal (') is determined by the internal error-trap mode:

0    abort execution (set by Trap: @ or .)
1    suspend execution and run the debugger
2    collect stack trace and abort (set by .Q.trp)

Mode 2 (dump stack trace) is now default for loading scripts non-interactively (e.g. with -q).

During abort, the stack is unwound up to the nearest trap (@ or . or .Q.trp). The error-trap mode is always initially set to 1 for console input and to 0 for sync message processing.

\e sets the mode applied before async and HTTP callbacks run. Thus, \e 1 will cause the relevant handlers to break into the debugger, while \e 2 will dump the backtrace either to the server console (for async), or into the socket (for HTTP).

q)\e 2
q)'type             / incoming async msg signals 'type
  [2]  f@:{x*y}
            ^
  [1]  f:{{x*y}[x;3#x]}
          ^
  [0]  f `a
       ^
q)\e 1
q)'type             
  [2]  f@:{x*y}
            ^
q))                 / the server is suspended in a debug session

Keywords

Q is an embedded domain-specific language. Many of its keywords are defined as lambdas or projections, and can suspend as described.


Display, show
Q for Mortals 3: §10.2 Debugging