JuliusBrussee/caveman · error

unknown argument ${arg}

Error message

unknown argument ${arg}

What it means

Thrown by the release-binary build script's argument parser when it encounters a CLI argument that is not --out, --target, or --list. The parser is intentionally exhaustive with no pass-through, so any unrecognized flag aborts before a potentially long Go cross-compile starts.

Source

Thrown at scripts/build-release-binaries.mjs:52

  return targets.flatMap(([goos, arch]) =>
    RELEASE_BINARIES.map(([name]) => releaseArtifactName(name, goos, arch)));
}

function parseArgs(argv) {
  let out = resolve(root, "dist", "binaries");
  const targets = [];
  for (let index = 0; index < argv.length; index++) {
    const arg = argv[index];
    if (arg === "--out") out = resolve(argv[++index] ?? "");
    else if (arg === "--target") {
      const value = argv[++index] ?? "";
      const [goos, arch] = value.split("/");
      if (!RELEASE_TARGETS.some(([knownOS, knownArch]) => knownOS === goos && knownArch === arch)) {
        throw new Error(`unsupported release target ${JSON.stringify(value)}`);
      }
      targets.push([goos, arch]);
    } else if (arg === "--list") return { out, targets: RELEASE_TARGETS, list: true };
    else throw new Error(`unknown argument ${arg}`);
  }
  return { out, targets: targets.length ? targets : RELEASE_TARGETS, list: false };
}

function build({ out, targets }) {
  mkdirSync(out, { recursive: true });
  const artifacts = [];
  for (const [goos, arch] of targets) {
    for (const [name, packagePath] of RELEASE_BINARIES) {
      const artifact = releaseArtifactName(name, goos, arch);
      const output = join(out, artifact);
      process.stderr.write(`build ${artifact}\n`);
      const result = spawnSync("go", ["build", "-trimpath", "-o", output, packagePath], {
        cwd: root,
        env: { ...process.env, CGO_ENABLED: "0", GOOS: goos, GOARCH: arch },
        stdio: "inherit",
      });
      if (result.error) throw result.error;

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Remove the unrecognized flag — the script supports only --out <dir>, --target <goos/goarch> (repeatable), and --list.
  2. Run the script with no arguments or --list to see the usage implied by the supported flags and defaults.
  3. Check for shell expansion: quote arguments and ensure no stray tokens (e.g. an unquoted *) are appended.

Example fix

# before
node scripts/build-release-binaries.mjs --verbose --target linux/amd64
# after
node scripts/build-release-binaries.mjs --target linux/amd64
Defensive patterns

Strategy: validation

Validate before calling

const ALLOWED = new Set(["--out", "--target", "--list"]);
for (const a of argv) {
  const flag = a.startsWith("-") ? a : null;
  if (flag && !ALLOWED.has(flag) && !ALLOWED.has(flag.split("=")[0])) {
    throw new Error(`unsupported flag ${flag}; allowed: ${[...ALLOWED].join(" ")}`);
  }
}

Prevention

When it happens

Trigger: Running scripts/build-release-binaries.mjs with a flag like --jobs 4, --verbose, -t linux/amd64, or a positional argument; or passing a flag that belongs to a different script (e.g. --os instead of --target).

Common situations: Copy-pasting a command from docs of a different version of the script; muscle-memory flags from goreleaser or similar tools; a trailing typo or unquoted shell glob expanding into extra args.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/6c2bce262c2cf45a. Report an issue: GitHub.