Hmbown/CodeWhale · error · Error

GitHub Release ${tag} returned invalid JSON: ${error.message

Error message

GitHub Release ${tag} returned invalid JSON: ${error.message}

What it means

The gh api subprocess exited 0 but its stdout could not be JSON.parsed. The script expects the raw REST release object on stdout, so any pollution there — a gh warning, an active pager, a GH_BIN wrapper that reformats output — breaks parsing. The underlying SyntaxError message is appended to name where parsing failed.

Source

Thrown at scripts/release/ensure-release-assets-absent.js:49

    output = exec(ghBin, ["api", endpoint], {
      encoding: "utf8",
      maxBuffer: 10 * 1024 * 1024,
      stdio: ["ignore", "pipe", "pipe"],
    });
  } catch (error) {
    if (isNotFoundError(error)) {
      return null;
    }
    const detail = String(error && error.stderr ? error.stderr : "").trim();
    throw new Error(
      `Could not inspect GitHub Release ${tag}${detail ? `: ${detail}` : ""}`,
    );
  }

  try {
    return JSON.parse(output);
  } catch (error) {
    throw new Error(`GitHub Release ${tag} returned invalid JSON: ${error.message}`);
  }
}

function assertReleaseAssetsAbsent(release, tag) {
  if (release === null) {
    return;
  }
  if (!release || !Array.isArray(release.assets)) {
    throw new Error(`GitHub Release ${tag} did not provide an asset inventory`);
  }
  if (release.assets.length === 0) {
    return;
  }

  const names = release.assets.map((asset) => asset && asset.name).filter(Boolean);
  const inventory = names.length > 0 ? names.join(", ") : `${release.assets.length} unnamed asset(s)`;
  throw new Error(
    `Refusing to replace existing assets for ${tag}: ${inventory}. ` +

View on GitHub (pinned to 8880682c63)

Solutions

  1. Reproduce manually: gh api repos/OWNER/REPO/releases/tags/vX.Y.Z | head -c 200 to see what stdout actually contains
  2. Unset GH_PAGER for the step (env -u GH_PAGER ...) and disable gh output formatting
  3. If GH_BIN is a wrapper, keep stdout pristine — send any diagnostics to stderr only

Example fix

# before: GH_PAGER=less pollutes stdout -> invalid JSON

# after
env -u GH_PAGER GH_BIN=gh node scripts/release/ensure-release-assets-absent.js acme/codewhale v1.2.3
Defensive patterns

Strategy: validation

Validate before calling

const { execFileSync } = require("node:child_process");
function ghStdoutIsCleanJson() {
  const probe = execFileSync(process.env.GH_BIN || "gh", ["api", "rate_limit"], { encoding: "utf8" });
  try {
    JSON.parse(probe);
    return true;
  } catch {
    return false;
  }
}

Prevention

When it happens

Trigger: GH_PAGER or gh config writing to stdout in CI; GH_BIN pointing at a wrapper (jq filter, tee, formatter); gh emitting a notice line before the JSON; a proxy injecting a banner into piped output.

Common situations: Custom GH_BIN shims inside the workflow; environment-wide pager settings; global gh config changed output formatting; test harnesses stubbing gh with echo.

Understand the failure class

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/ea6e4f13e977efba. Report an issue: GitHub.