Upload debug symbols for Go

The Go SDK resolves stack traces in-process from the Go runtime, so captured frames always include file names, line numbers, and function names. Uploading debug symbols improves on that: PostHog symbolicates frames server-side from the exact build that crashed, resolves inlined calls precisely, and can display the source code around each frame.

Version requirements
  • posthog-go 1.20.0 or later, which records the instruction addresses and binary identity server-side symbolication needs. We recommend the latest version.
  • The latest CLI. Linux binaries work with CLI 0.7.32 or later; uploading macOS Go binaries directly is newer, so update if you have an older install.
  1. Download CLI

    Required

    Install posthog-cli:

    npm install -g @posthog/cli

  2. Authenticate

    Required

    To authenticate the CLI, call the login command. This opens your browser where you select your organization, project, and API scopes to grant:

    Terminal
    posthog-cli login

    If you are using the CLI in a CI/CD environment such as GitHub Actions, you can set environment variables to authenticate:

    Environment VariableDescriptionSource
    POSTHOG_CLI_HOSTThe PostHog host to connect to [default: https://us.posthog.com]Project settings
    POSTHOG_CLI_PROJECT_IDPostHog project IDProject settings
    POSTHOG_CLI_API_KEYPersonal API key with error tracking write and organization read scopesAPI key settings

    You can also use the --host option instead of the POSTHOG_CLI_HOST environment variable to target a different PostHog instance or region. For EU users:

    Terminal
    posthog-cli --host https://eu.posthog.com [CMD]

  3. Build with the right linker flags

    Required

    Go embeds DWARF debug info in every binary by default, but the SDK and CLI need a little help depending on the platform.

    On Linux, add a GNU build ID — the unique identifier PostHog uses to match stack frames to uploaded symbols. Go doesn't emit one by default:

    Terminal
    go build -ldflags="-B gobuildid" -o my-app .

    On macOS, keep the DWARF uncompressed. Binaries always carry a Mach-O UUID, so there is no build ID step, but Go compresses debug info by default and compressed DWARF can't be used for symbolication yet:

    Terminal
    go build -ldflags="-compressdwarf=false" -o my-app .

    Watch out for flags that remove what the upload needs: -ldflags="-w" or -ldflags="-s" strip DWARF entirely, and -trimpath rewrites the source paths that --include-source relies on.

  4. Build and upload

    Required

    Point the CLI at the directory containing your built binary:

    Terminal
    posthog-cli symbol-sets upload --directory ./bin

    The CLI scans the directory and uploads every executable that carries debug info and an identity, skipping everything else. On macOS the Go binary uploads directly — Go never produces a .dSYM bundle, and none is needed. Universal (fat) binaries upload one symbol set per architecture slice. Windows binaries are not supported yet: the SDK sends plain runtime-resolved frames there.

    Run this as part of the same pipeline that produces your production binary. Each build has its own identity, so symbols must be re-uploaded for every build you deploy.

  5. Optional: Include source code context

    Optional

    By default, only debug symbols are uploaded. To also display the source code around each frame in your stack traces, add --include-source:

    Terminal
    posthog-cli symbol-sets upload --directory ./bin --include-source

    This bundles the project source files referenced by the debug info into the upload. It increases upload size, so only enable it if you want source context in the error tracking UI. It also requires building without -trimpath, since the CLI reads sources from the paths recorded at compile time.

  6. Optional: Upload from CI

    Optional

    In CI, authenticate with environment variables instead of posthog-cli login. For GitHub Actions:

    YAML
    - name: Build release binary
    run: go build -ldflags="-B gobuildid" -o bin/my-app .
    - name: Upload debug symbols
    run: posthog-cli symbol-sets upload --directory ./bin
    env:
    POSTHOG_CLI_API_KEY: ${{ secrets.POSTHOG_CLI_API_KEY }}
    POSTHOG_CLI_PROJECT_ID: ${{ secrets.POSTHOG_CLI_PROJECT_ID }}

    Scope the credentials to the upload step only — the build itself doesn't need them.

    The CLI defaults to US Cloud. If you are on EU Cloud or self-hosted, also set POSTHOG_CLI_HOST (for example https://eu.posthog.com).

    If your binary is built inside a Dockerfile, run the upload in the build stage right after the build, and pass the credentials in as build secrets so they never reach the runtime image.

  7. Verify debug symbols upload

    Checkpoint
    Confirm that debug symbols are successfully uploaded to PostHog.Check symbol sets in PostHog
  8. Test it end-to-end

    Optional

    Capture a test exception from the same binary the symbols were uploaded for:

    Go
    exception := posthog.NewDefaultException(
    time.Now(),
    "test_user",
    "TestError",
    "This is a test exception from Go",
    )
    client.Enqueue(exception)
    client.Close()

    Run the binary, then check the error tracking issues view: the stack trace should resolve against the uploaded symbols, including source context if you uploaded with --include-source. A rebuild changes the binary's identity, so if you rebuild, upload again before testing.

Community questions

Was this page useful?