oven-sh/bun · error · Error

BUILDKITE_AGENT_TOKEN not set and no existing buildkite-agen

Error message

BUILDKITE_AGENT_TOKEN not set and no existing buildkite-agent.cfg to reuse

What it means

scripts/agent.mjs provisions a machine as a BuildKite agent; on macOS it needs either the BUILDKITE_AGENT_TOKEN environment variable or an existing buildkite-agent.cfg to reuse. With neither, it throws before writing any launchd configuration, so you cannot accidentally register an agent with no credentials.

Source

Thrown at scripts/agent.mjs:136

          --background \\
          --make-pidfile \\
          --stdout ${escape(agentLogPath)} \\
          --stderr ${escape(agentLogPath)}"

        depend() {
          need net
          use dns logger
        }
      `;
      writeFile(servicePath, service, { mode: 0o755 });
      await spawnSafe(["rc-update", "add", "buildkite-agent", "default"], { stdio: "inherit", privileged: true });
    }

    if (isMacOS) {
      const queue = cliOptions.queue || getEnv("BUILDKITE_AGENT_QUEUE", false) || "test-darwin";
      const token = getEnv("BUILDKITE_AGENT_TOKEN", false);
      if (!token && !existsSync(cfgPath)) {
        throw new Error("BUILDKITE_AGENT_TOKEN not set and no existing buildkite-agent.cfg to reuse");
      }

      // `install` runs via sudo, so process.env.USER is "root". The launchd
      // service must run as the real login user (whose ~/Library the cfg and
      // build dirs live under), and the files we write here must be owned by
      // them so the service can read them.
      const runAsUser = process.env.SUDO_USER || process.env.USER || "administrator";

      for (const dir of [homePath, cachePath, logsPath]) {
        mkdir(dir);
      }

      // Copy this script and its imports into homePath so the launchd plist
      // doesn't depend on the checkout that ran `install` sticking around.
      const srcDir = fileURLToPath(new URL(".", import.meta.url));
      for (const f of ["agent.mjs", "utils.mjs"]) {
        copyFileSync(join(srcDir, f), join(homePath, f));
      }

View on GitHub (pinned to 8c5296ac45)

Solutions

  1. Export the token first: BUILDKITE_AGENT_TOKEN=... (create one in BuildKite org settings > Agents)
  2. Point the script at an existing buildkite-agent.cfg if the machine was previously registered
  3. Pass sudo -E (or configure env_keep) if running the installer through sudo so the variable survives
  4. Also set BUILDKITE_AGENT_QUEUE if you need a queue other than the default 'test-darwin'

Example fix

# before
node scripts/agent.mjs install   # no token, no cfg -> throws

# after
export BUILDKITE_AGENT_TOKEN=...
node scripts/agent.mjs install
Defensive patterns

Strategy: validation

Validate before calling

import { existsSync } from 'node:fs';
const hasToken = Boolean(process.env.BUILDKITE_AGENT_TOKEN);
if (!hasToken && !existsSync(cfgPath)) {
  throw new Error('set BUILDKITE_AGENT_TOKEN (BuildKite > Agents > New Agent) before running install');
}

Prevention

When it happens

Trigger: Running the script's install/setup command on a Mac without exporting BUILDKITE_AGENT_TOKEN and with no prior agent configuration at the expected cfgPath.

Common situations: Onboarding a new CI mac machine and forgetting the token from the BuildKite organization settings; running through sudo where the env var is stripped (env_reset); a fresh macOS runner image.

Related errors


AI-assisted analysis of oven-sh/bun@8c5296ac45 (2026-08-16). Data as JSON: /api/errors/a79ae79961bda122. Report an issue: GitHub.