can1357/oh-my-pi · error

agent:// URL cannot combine path extraction with ?q=

Error message

agent:// URL cannot combine path extraction with ?q=

What it means

agent:// URLs support two mutually exclusive extraction mechanisms: a slash path (agent://<id>/<path>) and a query string (agent://<id>?q=<query>). If a URL supplies both a non-trivial pathname and a non-empty ?q= parameter, the handler cannot decide which extraction to apply and throws. This is a strict ambiguity check on URL shape.

Source

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

 * with optional JSON extraction.
 */
export class AgentProtocolHandler implements ProtocolHandler {
	readonly scheme = "agent";
	readonly immutable = true;

	async resolve(url: InternalUrl, context?: ResolveContext): Promise<InternalResource> {
		const outputId = url.rawHost || url.hostname;
		if (!outputId) {
			throw new Error("agent:// URL requires an output ID: agent://<id>");
		}

		const urlPath = url.pathname;
		const queryParam = url.searchParams.get("q");
		const hasPathExtraction = urlPath && urlPath !== "/" && urlPath !== "";
		const hasQueryExtraction = queryParam !== null && queryParam !== "";

		if (hasPathExtraction && hasQueryExtraction) {
			throw new Error("agent:// URL cannot combine path extraction with ?q=");
		}

		const registry = AgentRegistry.global();
		const rootSessionFile = context?.sessionFile
			? await ensurePersistedRoster(registry, context.sessionFile)
			: undefined;
		// The caller root's canonical artifact directory (its session file minus
		// the `.jsonl` suffix) is scanned FIRST, ahead of every process-global
		// registry dir. The roster ref this refresh installs for the caller's
		// parked id contributes only its nested child dir, not the root dir that
		// actually holds `<id>.md` — and with two coexisting roots the global
		// `Main` ref can belong to the other root, whose dir would otherwise win
		// the first-hit id map for a shared id. No caller session file: keep the
		// pre-existing global scan untouched.
		const dirs = artifactsDirsFromRegistry(
			rootSessionFile ? { preferredDir: rootSessionFile.slice(0, -6) } : undefined,
		);
		if (dirs.length === 0) {

View on GitHub (pinned to 9690622007)

Solutions

  1. Remove the ?q= parameter and express the extraction as a path, keeping one mechanism
  2. Or remove the path portion so only ?q= remains: agent://<id>?q=<query>
  3. If building URLs dynamically, strip the pathname when a q param is present (or vice versa)

Example fix

// before
await handler.resolve(parseUrl("agent://out1/foo/bar?q=.items[0]"), ctx);
// after
await handler.resolve(parseUrl("agent://out1?q=.foo.bar.items[0]"), ctx);
Defensive patterns

Strategy: validation

Validate before calling

const hasPath = url.pathname && url.pathname !== "/";
const hasQuery = url.searchParams.get("q") !== null && url.searchParams.get("q") !== "";
if (hasPath && hasQuery) throw new Error("agent:// URL cannot combine path extraction with ?q=");

Type guard

function usesSingleExtraction(url: InternalUrl): boolean {
  const hasPath = Boolean(url.pathname && url.pathname !== "/");
  const q = url.searchParams.get("q");
  const hasQuery = q !== null && q !== "";
  return !(hasPath && hasQuery);
}

Prevention

When it happens

Trigger: Calling resolve() with a URL that has both a pathname other than '' and '/', and a non-empty 'q' search param — e.g. 'agent://out1/foo/bar?q=.items[0]' or 'agent://out1/data.json?q=results'.

Common situations: Appending ?q= to a URL that already contains a path-based extraction (copy-pasted from an example that used the other form); code that programmatically appends query params to a base URL that already has path segments; migrating between the two extraction forms and leaving both in place.

Related errors


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