Skip to main content

Interactive Debugging

Pipeline failures can be both frustrating and lead to wasted resources as the team seeks to understand what went wrong and why. Dagger's interactive debugging feature is an invaluable tool in this situation.

Dagger lets users drop in to an interactive shell when a pipeline run fails, with all the context at the point of failure. This is similar to a debugger experience, but without needing to set breakpoints explicitly. No changes are required to your code.

Here's an example of a pipeline run failing, and Dagger opening an interactive terminal at the point of failure:

package main

import (
"context"

"dagger.io/dagger/dag"
)

type MyModule struct{}

func (m *MyModule) Foo(ctx context.Context) (string, error) {
return dag.Container().
From("alpine:latest").
WithExec([]string{"sh", "-c", "echo hello world > /foo"}).
WithExec([]string{"cat", "/FOO"}). // deliberate error
Stdout(ctx)
}

// run with dagger call --interactive foo

See it in action:

Interactive debugging

You can also set one or more explicit breakpoints in your pipeline, which then starts an interactive terminal session at each breakpoint. This lets you inspect a directory or a container at any point in your pipeline run, with all the necessary context available to you.

Here's another example, which opens an interactive terminal at two different points in a pipeline run to inspect the built container:

package main

import (
"context"
"dagger/my-module/internal/dagger"

"dagger.io/dagger/dag"
)

type MyModule struct{}

func (m *MyModule) Foo(ctx context.Context) *dagger.Container {
return dag.Container().
From("alpine:latest").
Terminal().
WithExec([]string{"sh", "-c", "echo hello world > /foo"}).
Terminal()
}

See it in action:

Debugging with breakpoints