can1357/oh-my-pi · error · ToolError

Cannot search URL output because this session cannot materia

Error message

Cannot search URL output because this session cannot materialize read artifacts.

What it means

materializeReadUrlContent persists fetched URL content (raw or rendered) into the session's artifacts directory so it can be searched (e.g. by the grep tool over URL output). If session.getArtifactsDir() returns undefined — the session does not support artifact materialization — there is nowhere to write the content, so it throws instead of degrading. This is a session-capability contract error.

Source

Thrown at packages/coding-agent/src/tools/fetch.ts:1628

		if (artifactPath) return { ...entry, artifactPath };
	}
	const artifact = await persistReadUrlArtifact(session, entry.output);
	return artifact?.id ? { ...entry, artifactId: artifact.id, artifactPath: artifact.path } : entry;
}

function readUrlContentExtension(finalUrl: string): string {
	try {
		const ext = getFilenameExtensionHint(new URL(finalUrl).pathname);
		return ext && /^\.[a-z0-9][a-z0-9+.-]{0,15}$/i.test(ext) ? ext : ".txt";
	} catch {
		return ".txt";
	}
}

async function materializeReadUrlContent(session: ToolSession, entry: ReadUrlEntry, raw: boolean): Promise<string> {
	const root = session.getArtifactsDir?.();
	if (!root) {
		throw new ToolError("Cannot search URL output because this session cannot materialize read artifacts.");
	}
	const dir = path.join(root, "url-search");
	await fs.mkdir(dir, { recursive: true });
	const hash = Bun.hash(`${raw ? "raw" : "rendered"}:${entry.details.finalUrl}`).toString(36);
	const contentPath = path.join(dir, `${hash}${readUrlContentExtension(entry.details.finalUrl)}`);
	await Bun.write(contentPath, entry.content);
	return contentPath;
}

/** Fetch and render a URL for a read or search operation. */
export async function fetchReadUrl(
	session: ToolSession,
	params: { path: string; raw?: boolean },
	signal?: AbortSignal,
	options?: { ensureArtifact?: boolean },
): Promise<ReadUrlEntry> {
	const { path: url, raw = false } = params;

View on GitHub (pinned to 9690622007)

Solutions

  1. Provide a working getArtifactsDir() on the session pointing at a writable directory.
  2. Ensure the standard session construction path is used so artifacts are initialized.
  3. Perform content searching outside the tool (fetch the URL yourself and grep the response) when artifacts are intentionally unavailable.

Example fix

// before: custom session without artifacts
const session = { /* no getArtifactsDir */ } as ToolSession;
// after
const session = { ...base, getArtifactsDir: () => "/tmp/my-agent-artifacts" };
Defensive patterns

Strategy: validation

Validate before calling

const root = session.getArtifactsDir?.();
if (!root) {
  // skip URL search or fetch/grep the content yourself
  return null;
}

Type guard

function supportsArtifacts(s: ToolSession): boolean { return typeof s.getArtifactsDir === "function" && typeof s.getArtifactsDir() === "string"; }

Try / catch

try {
  await searchUrlOutput(session, entry, query);
} catch (e) {
  if (e instanceof ToolError && e.message.includes("cannot materialize read artifacts")) {
    // fall back to direct fetch + local grep
  } else throw e;
}

Prevention

When it happens

Trigger: Triggering a URL-search flow (searching output of a previously fetched URL) on a session whose getArtifactsDir is absent or returns undefined — e.g. minimal/embedded ToolSession implementations or headless transports that skip artifact setup.

Common situations: Embedding the SDK with a hand-rolled ToolSession missing getArtifactsDir; running in constrained environments where artifact dirs are disabled; RPC/remote sessions without artifact passthrough.

Related errors


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