can1357/oh-my-pi · error · ToolError

GitHub CLI returned invalid JSON output.

Error message

GitHub CLI returned invalid JSON output.

What it means

github.json<T>() runs the `gh` CLI and parses stdout as JSON. If `gh` exits 0 but its stdout is not parseable JSON, the wrapper converts JSON.parse's failure into a ToolError so callers get a clear message instead of a SyntaxError.

Source

Thrown at packages/coding-agent/src/utils/github.ts:131

				stdout: trim ? stdout.trim() : stdout,
				stderr: trim ? stderr.trim() : stderr,
			};
		} catch (error) {
			if (signal?.aborted) throw new ToolAbortError();
			if (timeoutSignal.aborted) throw new ToolError(`GitHub CLI command timed out: gh ${args.join(" ")}`);
			throw error;
		}
	},

	/** Run `gh` and parse stdout as JSON. Throws on non-zero exit or invalid JSON. */
	async json<T>(cwd: string, args: string[], signal?: AbortSignal, options?: GhCommandOptions): Promise<T> {
		const result = await github.run(cwd, args, signal, options);
		if (result.exitCode !== 0) throw new ToolError(formatGhFailure(args, result.stdout, result.stderr, options));
		if (!result.stdout) throw new ToolError("GitHub CLI returned empty output.");
		try {
			return JSON.parse(result.stdout) as T;
		} catch {
			throw new ToolError("GitHub CLI returned invalid JSON output.");
		}
	},

	/** Run `gh` and return stdout as text. Throws on non-zero exit. */
	async text(cwd: string, args: string[], signal?: AbortSignal, options?: GhCommandOptions): Promise<string> {
		const result = await github.run(cwd, args, signal, options);
		if (result.exitCode !== 0) throw new ToolError(formatGhFailure(args, result.stdout, result.stderr, options));
		return result.stdout;
	},
};

View on GitHub (pinned to 9690622007)

Solutions

  1. Add the --json flag with required fields to the gh args (e.g. pr list --json number,title).
  2. Run the same command manually with gh ... and inspect what non-JSON text is emitted on stdout.
  3. Check the gh version (gh --version) and upgrade if it does not support the requested --json fields.
  4. Use github.text() instead if the endpoint legitimately returns plain text.
  5. Remove wrappers/aliases around gh that inject extra output into stdout.

Example fix

// before: await github.json(cwd, ["pr", "list", "--limit", "5"]);  // after: await github.json(cwd, ["pr", "list", "--limit", "5", "--json", "number,title,state"]);
Defensive patterns

Strategy: try-catch

Validate before calling

const args = ["pr", "list", "--json", "number,title"]; if (!args.includes("--json")) throw new Error("github.json() requires --json in args");

Type guard

function isJsonObject(v: unknown): v is Record<string, unknown> { return typeof v === "object" && v !== null && !Array.isArray(v); } // narrow the parsed value after JSON.parse

Try / catch

try { const data = await github.json<MyType>(cwd, args); } catch (err) { if (err instanceof ToolError && /invalid JSON/.test(err.message)) { const raw = await github.text(cwd, args); /* inspect raw output or fall back */ } else { throw err; } }

Prevention

When it happens

Trigger: Calling github.json() with args whose output is not JSON: missing --json flag (e.g. `gh pr list` without --json), gh emitting warnings or progress text on stdout, an aliased or wrapped gh producing human output, or a non-JSON output format (--template).

Common situations: Constructing gh args by hand and forgetting --json <fields>; older gh versions lacking a JSON field; gh printing notices alongside data; shell wrappers that prefix output.

Understand the failure class

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/ea6007cbe40175a6. Report an issue: GitHub.