can1357/oh-my-pi · error

Output ${scan.matchedId} is not valid JSON: ${message}

Error message

Output ${scan.matchedId} is not valid JSON: ${message}

What it means

AgentProtocolHandler.resolve (packages/coding-agent/src/internal-urls/agent-protocol.ts:113) wraps JSON.parse failures when an agent:// URL requests JSON extraction via a ?q= query or a slash path. It means the artifact file backing the output ID exists but its content is not parseable JSON, so jq-style extraction cannot proceed. The original JSON.parse message (position, unexpected token) is appended to the error.

Source

Thrown at packages/coding-agent/src/internal-urls/agent-protocol.ts:113

			const availableStr = scan.availableIds.size > 0 ? [...scan.availableIds].join(", ") : "none";
			throw new Error(`Not found: ${target}\nAvailable: ${availableStr}`);
		}

		const rawContent = await Bun.file(scan.foundPath).text();
		const notes: string[] = [];
		let content = rawContent;
		let contentType: InternalResource["contentType"] = "text/markdown";

		// Extraction applies only when the URL did NOT resolve to a nested output
		// (a slash that named a real child is a hierarchy hop, not a jq path).
		const extract = hasQueryExtraction || (hasPathExtraction && scan.matchedId !== nestedId);
		if (extract) {
			let jsonValue: unknown;
			try {
				jsonValue = JSON.parse(rawContent);
			} catch (err) {
				const message = err instanceof Error ? err.message : String(err);
				throw new Error(`Output ${scan.matchedId} is not valid JSON: ${message}`);
			}

			const query = hasQueryExtraction ? queryParam! : pathToQuery(urlPath);
			if (query) {
				const extracted = applyQuery(jsonValue, query);
				try {
					content = JSON.stringify(extracted, null, 2) ?? "null";
				} catch {
					content = String(extracted);
				}
				notes.push(`Extracted: ${query}`);
			} else {
				content = JSON.stringify(jsonValue, null, 2);
			}
			contentType = "application/json";
		}

		return {

View on GitHub (pinned to 9690622007)

Solutions

  1. Resolve the bare URL (agent://<id> with no path or ?q=) to inspect the raw content and confirm whether it is JSON.
  2. Remove the ?q= or slash-path extraction from the URL and consume the output as text/markdown.
  3. If JSON is expected, fix the producing tool/agent call so it emits valid JSON (check the appended JSON.parse message for the offending position).
  4. Check the referenced artifact file on disk (sourcePath shown in prior resolves) for truncation or manual edits.

Example fix

// before
const out = await resolveUrl(new URL("agent://scan_1?q=.findings"));
// after — inspect first, extract only if JSON
const raw = await resolveUrl(new URL("agent://scan_1"));
const url = raw.contentType === "application/json"
  ? new URL("agent://scan_1?q=.findings")
  : new URL("agent://scan_1");
const out2 = await resolveUrl(url);
Defensive patterns

Strategy: try-catch

Validate before calling

const raw = await resolveUrl(new URL(`agent://${id}`));
let parsed: unknown;
try { parsed = JSON.parse(raw.content); } catch { parsed = undefined; }
if (parsed === undefined) {
  // skip ?q=/path extraction; consume raw.content as text
}

Type guard

function isJsonResource(r: { content: string; contentType: string }): boolean {
  if (r.contentType !== "application/json" && r.contentType !== "text/markdown") return false;
  try { JSON.parse(r.content); return true; } catch { return false; }
}

Try / catch

try {
  const out = await resolveUrl(new URL(`agent://${id}?q=.field`));
} catch (err) {
  if (err instanceof Error && err.message.startsWith(`Output ${id} is not valid JSON`)) {
    const raw = await resolveUrl(new URL(`agent://${id}`)); // fall back to raw text
  } else throw err;
}

Prevention

When it happens

Trigger: Calling agent://<id>?q=.field or agent://<id>/path when <id>.md contains plain text/markdown rather than JSON; the output was written by a tool that returns prose, or the extraction form was used on a non-JSON output.

Common situations: Pointing ?q= extraction at a markdown report output instead of a JSON tool output; an upstream tool changed its output format from JSON to text between versions; a hand-edited or truncated artifact file; copying an output ID from a different tool whose artifacts are textual.

Related errors


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