tinyhumansai/openhuman · error · Error

gh api PATCH failed: ${r.stderr?.trim() || ""}

Error message

gh api PATCH failed: ${r.stderr?.trim() || ""}

What it means

postOrUpdateTrackingComment() in scripts/agent-batch/status.mjs updates the previously-found tracking comment via `gh api --method PATCH repos/<repo>/issues/comments/<id> -F body=@-` (body on stdin to dodge ARG_MAX) and throws with gh's stderr on non-zero exit. This branch runs when the comment listing DID find a comment carrying the <!-- batch:<id> --> marker, and patches it in place with the freshly rendered table.

Source

Thrown at scripts/agent-batch/status.mjs:183

  } else {
    const id = existing[0].id;
    // Pass the comment body via stdin (-F body=@-) rather than a command-line
    // arg. Long markdown tables can grow large and -f body=${body} risks
    // hitting OS argv length limits (ARG_MAX).
    const r = spawnSync(
      "gh",
      [
        "api",
        "--method",
        "PATCH",
        `repos/${spec.base_repo}/issues/comments/${id}`,
        "-F",
        "body=@-",
      ],
      { encoding: "utf8", input: body },
    );
    if (r.status !== 0) {
      throw new Error(`gh api PATCH failed: ${r.stderr?.trim() || ""}`);
    }
    process.stdout.write(
      `[agent-batch] updated tracking comment ${existing[0].html_url}\n`,
    );
  }
}

function main() {
  const { positional, flags } = parseArgs(process.argv.slice(2));
  if (flags.help || flags.h || flags["?"]) {
    process.stdout.write(`${usage()}\n`);
    process.exit(0);
  }
  const specPath = positional[0];
  if (!specPath) {
    process.stderr.write(`${usage()}\n`);
    process.exit(2);
  }

View on GitHub (pinned to a221052e0d)

Solutions

  1. Re-run the command — if the comment was deleted, the listing step now finds none and the script posts a fresh comment instead of PATCHing
  2. Check the token has issues:write permission on the target repo (`gh auth status`)
  3. Delete the orphaned marker comment yourself if you intentionally removed the old one, so the next run starts clean at the post path
  4. Space out concurrent --post invocations to avoid racing the same comment id

Example fix

# before
$ node scripts/agent-batch/status.mjs batch.json --post
Error: gh api PATCH failed: HTTP 404: Not Found

# after (comment was deleted; re-run posts a new one)
$ node scripts/agent-batch/status.mjs batch.json --post
[agent-batch] posted new tracking comment on #1234
Defensive patterns

Strategy: retry

Validate before calling

// Re-verify the comment still exists right before patching
const check = spawnSync("gh", ["api", `repos/${spec.base_repo}/issues/comments/${id}`], { encoding: "utf8" });
if (check.status !== 0) {
  // comment vanished — fall back to the post path instead of PATCHing
  return postNewComment(spec, body);
}

Try / catch

try {
  await patchComment(id, body);
} catch (e) {
  if (/gh api PATCH failed/.test(e.message) && /404/.test(e.message)) {
    return postNewComment(spec, body); // deleted comment → post a fresh one
  }
  if (/rate limit/i.test(e.message)) { await sleep(30_000); return patchComment(id, body); }
  throw e;
}

Prevention

When it happens

Trigger: A --post run where the comment id captured from the listing step no longer exists at PATCH time (someone deleted the tracking comment between the list and the patch), the token lacks issues:write, or a rate limit/network error hits the PATCH. The id comes from existing[0].id, so two humans running --post concurrently against the same batch can also race one comment out of existence.

Common situations: Maintainers deleting a stale tracking comment while an automated status loop is mid-update; read-only tokens reaching the PATCH stage because the earlier listing only needed read; primary/secondary rate limits during long-lived monitoring.

Related errors


AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16). Data as JSON: /api/errors/a0bb5d4aa8d3eb45. Report an issue: GitHub.