4.3.5 Starlark Debugger

recommended

The Starlark debugger is the tool for the moment when static inspection stops being enough. It lets a ruleset author attach to Bazel while .bzl code is being loaded or analyzed, set breakpoints, step through statements, and inspect the Starlark state that led to a generated target, provider value, or transition result like the ones covered in 4.7.2 Starlark Transitions.1

Start the debug build, then attach a client
Bazel pauses loading or analysis. A separate client attaches and tells it when to continue.
1 · START BAZEL
Request the build with debugging enabled
bazel build --experimental_skylark_debug //pkg:target
2 · WAIT, THEN ATTACH
Bazel pauses for a separate client
Attach from an IDE or a standalone debugger client. An editor may connect through a DAP adapter.
breakpoints + control requests
3 · EVALUATED CODE
Control only the active Starlark path
Breakpoints fire in BUILD or .bzl code Bazel evaluates for this request.
loading + analysis, not action execution
pause
step
inspect
continue
Debug Starlark control flow here. Use aquery, subcommands, or sandbox tools for action execution.

Most Starlark problems should still start with cheaper tools. If a macro-generated rule looks wrong, inspect the expanded target with bazel query --output=build as in 4.3.2 Macro Expansion Inspection. If you only need to see a value once, print() from 4.3.1 Print Debugging is usually faster. The debugger earns its keep when control flow, mutable intermediate values, or a large ruleset make those snapshots too thin.2

What Attaches To What

The debug session starts from an ordinary Bazel build request. You run the build with the legacy-named debugger flag:

bazel build --experimental_skylark_debug //pkg:target

With that flag enabled, Bazel waits for a debugger to attach before it continues the Starlark evaluation for the requested build.1 The target still matters: breakpoints only fire for .bzl or BUILD code that Bazel actually evaluates for that request. A breakpoint in an unrelated package or an already-cached path may appear to do nothing until the relevant file is loaded again.3

Treat the flag as version-sensitive. Many debugger clients still use the legacy skylark spelling, and this flag is not covered by the local official CLI references. Before documenting it in a team workflow, verify the spelling and debugger support against your Bazel release and IDE adapter.

There are two practical client shapes. A standalone client such as stardbg can connect directly and give a browser or terminal debugging UI. IDE support usually goes through a debug adapter: the editor speaks DAP, the adapter translates IDE operations into the Starlark debugger protocol, and Bazel remains the server being debugged.1

# Terminal 1: start the debuggee
bazel build --experimental_skylark_debug //pkg:target

# Terminal 2: attach with your debugger client or IDE adapter

That two-process shape is the important mental model. The build command is not replaced by a special "debug build". It is the same build, paused at Starlark evaluation points, with an external client deciding when to continue.

What You Can Inspect

The debugger can list threads, show stack frames, set breakpoints, continue, pause, and step through Starlark statements. It can also inspect local and global variables, and for structured values it can ask for children so an IDE can render an expandable tree.1

That makes it especially useful for rule and macro authors. You can stop inside a macro implementation to see how caller-provided attrs are normalized before rule calls are emitted. You can stop inside a rule implementation to inspect ctx.attr, provider values, or the pieces that will become an action command line. In a transition implementation, stepping through the function can make the returned settings dictionary concrete instead of mysterious.1

The debugger does not show execution-phase output. It pauses while Bazel evaluates Starlark during loading and analysis. If the problem is the command line an action runs, its sandbox, or the files it consumes, continue with aquery, --subcommands, or --sandbox_debug instead.2

Sharp Edges

The debugger is experimental and has rough edges. It is a better fit for ruleset authors and Bazel developers than for application developers triaging normal build failures.1 Treat it as an escape hatch after the simpler tools have narrowed the problem.

Expression evaluation is limited. In the debugger protocol, evaluate requests run in global file scope, which means IDE hover values and conditional breakpoints are not as capable as in a language debugger for Python or Java. Some complex Starlark objects expose useful child structure, while provider objects are a notable weak spot for drill-down inspection.1

Caching can also confuse a first session. A breakpoint only triggers when Bazel re-evaluates that statement. If the long-lived server already has the relevant loaded or analyzed value, make a harmless edit or otherwise force the affected Starlark path to run again before assuming the breakpoint is wrong.3

key takeaway

Use the Starlark debugger when you need to watch loading- or analysis-phase Starlark logic unfold. It complements print(), query --output=build, and the REPL in 4.3.6 Starlark REPL / Playground, but it is not a general build failure debugger and it does not inspect action execution.

Check your understanding · 3 questions

1.When is the Starlark debugger a better choice than print() or bazel query --output=build?

Select one answer

2.True or false: Starlark debugger behavior and scope.

Choose True or False for each sentence

Breakpoints only fire for Starlark code Bazel evaluates for the requested build.
The debugger is primarily for inspecting execution-phase outputs.
A standalone client or IDE adapter attaches to a Bazel build that is waiting in Starlark evaluation.
Conditional breakpoints are a reliable substitute for writing simpler debug checks.

3.Which limitations should shape how you use the Starlark debugger?

Select all that apply

0 of 3 answered

Footnotes

  1. Starlark Debugger: Deep dive — debugger audience, server/client architecture, protocol operations, DAP adapter flow, and limitations. 1 2 3 4 5 6 7

  2. Sponsored Session: Enough Bazel to Be Dangerous: A Debugging Cookbook - Instructor: Alejandro Gomez — recommends query --output=build for macro expansion first, then the VS Code Starlark debugger or REPL when macro code itself must be debugged. 1 2

  3. Starlark Debugger: Deep dive — breakpoint workflow and the need for evaluated files to be in the requested build's Starlark path. 1 2