{"record":{"id":"1c00bfd1a8d6ca31","repo":"can1357/oh-my-pi","slug":"cannot-search-url-output-because-this-session-cann","errorCode":null,"errorMessage":"Cannot search URL output because this session cannot materialize read artifacts.","messagePattern":"Cannot search URL output because this session cannot materialize read artifacts\\.","errorType":"exception","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/fetch.ts","lineNumber":1628,"sourceCode":"\t\tif (artifactPath) return { ...entry, artifactPath };\n\t}\n\tconst artifact = await persistReadUrlArtifact(session, entry.output);\n\treturn artifact?.id ? { ...entry, artifactId: artifact.id, artifactPath: artifact.path } : entry;\n}\n\nfunction readUrlContentExtension(finalUrl: string): string {\n\ttry {\n\t\tconst ext = getFilenameExtensionHint(new URL(finalUrl).pathname);\n\t\treturn ext && /^\\.[a-z0-9][a-z0-9+.-]{0,15}$/i.test(ext) ? ext : \".txt\";\n\t} catch {\n\t\treturn \".txt\";\n\t}\n}\n\nasync function materializeReadUrlContent(session: ToolSession, entry: ReadUrlEntry, raw: boolean): Promise<string> {\n\tconst root = session.getArtifactsDir?.();\n\tif (!root) {\n\t\tthrow new ToolError(\"Cannot search URL output because this session cannot materialize read artifacts.\");\n\t}\n\tconst dir = path.join(root, \"url-search\");\n\tawait fs.mkdir(dir, { recursive: true });\n\tconst hash = Bun.hash(`${raw ? \"raw\" : \"rendered\"}:${entry.details.finalUrl}`).toString(36);\n\tconst contentPath = path.join(dir, `${hash}${readUrlContentExtension(entry.details.finalUrl)}`);\n\tawait Bun.write(contentPath, entry.content);\n\treturn contentPath;\n}\n\n/** Fetch and render a URL for a read or search operation. */\nexport async function fetchReadUrl(\n\tsession: ToolSession,\n\tparams: { path: string; raw?: boolean },\n\tsignal?: AbortSignal,\n\toptions?: { ensureArtifact?: boolean },\n): Promise<ReadUrlEntry> {\n\tconst { path: url, raw = false } = params;\n","sourceCodeStart":1610,"sourceCodeEnd":1646,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/fetch.ts#L1610-L1646","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Provide a working getArtifactsDir() on the session pointing at a writable directory.","Ensure the standard session construction path is used so artifacts are initialized.","Perform content searching outside the tool (fetch the URL yourself and grep the response) when artifacts are intentionally unavailable."],"exampleFix":"// before: custom session without artifacts\nconst session = { /* no getArtifactsDir */ } as ToolSession;\n// after\nconst session = { ...base, getArtifactsDir: () => \"/tmp/my-agent-artifacts\" };","handlingStrategy":"validation","validationCode":"const root = session.getArtifactsDir?.();\nif (!root) {\n  // skip URL search or fetch/grep the content yourself\n  return null;\n}","typeGuard":"function supportsArtifacts(s: ToolSession): boolean { return typeof s.getArtifactsDir === \"function\" && typeof s.getArtifactsDir() === \"string\"; }","tryCatchPattern":"try {\n  await searchUrlOutput(session, entry, query);\n} catch (e) {\n  if (e instanceof ToolError && e.message.includes(\"cannot materialize read artifacts\")) {\n    // fall back to direct fetch + local grep\n  } else throw e;\n}","preventionTips":["Always build sessions through the standard factory so getArtifactsDir is wired.","Check getArtifactsDir() before enabling URL-search features in embedders.","Ensure the artifacts directory is writable in the runtime environment."],"tags":["artifacts","session-capability","fetch-tool","url-search"],"backgroundTag":"missing-capability-unsupported-operation","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}