{"record":{"id":"5fe00fc2b54eb00e","repo":"can1357/oh-my-pi","slug":"e-instanceof-error-e-message-string-e-wraps","errorCode":null,"errorMessage":"e instanceof Error ? e.message : String(e) (wraps parseInternalUrl error)","messagePattern":"e instanceof Error \\? e\\.message : String\\(e\\) \\(wraps parseInternalUrl error\\)","errorType":"exception","errorClass":"ToolError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/tools/read.ts","lineNumber":2188,"sourceCode":"\n\t/**\n\t * Handle internal URLs (agent://, artifact://, memory://, skill://, rule://, local://, mcp://).\n\t * Supports pagination via offset/limit but rejects them when query extraction is used.\n\t */\n\tasync #handleInternalUrl(\n\t\turl: string,\n\t\tparsedSel: ParsedSelector,\n\t\tsignal?: AbortSignal,\n\t): Promise<AgentToolResult<ReadToolDetails>> {\n\t\tconst internalRouter = InternalUrlRouter.instance();\n\n\t\t// Check if URL has query extraction (agent:// only).\n\t\t// Use parseInternalUrl which handles colons in host (namespaced skills).\n\t\tlet urlMeta: InternalUrl;\n\t\ttry {\n\t\t\turlMeta = parseInternalUrl(url);\n\t\t} catch (e) {\n\t\t\tthrow new ToolError(e instanceof Error ? e.message : String(e));\n\t\t}\n\t\tconst scheme = urlMeta.protocol.replace(/:$/, \"\").toLowerCase();\n\t\tlet hasExtraction = false;\n\t\tif (scheme === \"agent\") {\n\t\t\tconst hasPathExtraction = urlMeta.pathname && urlMeta.pathname !== \"/\" && urlMeta.pathname !== \"\";\n\t\t\tconst queryParam = urlMeta.searchParams.get(\"q\");\n\t\t\tconst hasQueryExtraction = queryParam !== null && queryParam !== \"\";\n\t\t\thasExtraction = hasPathExtraction || hasQueryExtraction;\n\t\t}\n\t\tif (scheme === \"artifact\") {\n\t\t\treturn this.#readArtifactFile(urlMeta, parsedSel, signal);\n\t\t}\n\n\t\t// local:// files are real on-disk paths. Detect image files and emit a\n\t\t// decoded image block before the text-only resource contract UTF-8\n\t\t// decodes the binary into mojibake. The fast path returns null for\n\t\t// non-images, directories, listings, or any resolution failure, so the\n\t\t// text path below reproduces the router's not-found / symlink-escape","sourceCodeStart":2170,"sourceCodeEnd":2206,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/tools/read.ts#L2170-L2206","documentation":"Before resolving an agent:// (or other internal) URL with query extraction, ReadTool parses it via parseInternalUrl. Malformed URLs (bad scheme shape, unparseable host/colons) throw inside parseInternalUrl and are re-wrapped as a ToolError carrying the underlying message.","triggerScenarios":"Reading a URL like 'agent://::bad' or a URL whose host/path structure parseInternalUrl cannot parse — e.g. missing host, illegal colon placement in namespaced skill urls.","commonSituations":"Agent constructs resource URLs programmatically and mis-joins segments; skill names containing colons are not escaped per the namespaced-host convention; copy-pasted URLs mangled.","solutions":["Fix the URL structure: scheme://host/path with query params for extraction (e.g. agent://skill?q=...).","For skills with colons in names, follow the namespaced-host form supported by parseInternalUrl.","Validate the URL with new URL(...) or the same parser before calling read."],"exampleFix":"// before\nread(\"agent://my:skill/doc\")\n// after\nread(\"agent://my.skill/doc\")  // or namespaced host form accepted by parseInternalUrl","handlingStrategy":"validation","validationCode":"try { new URL(url.replace(/^agent:/, 'https:')); } catch { throw new Error('Malformed internal URL: ' + url); }","typeGuard":"function isParsableInternalUrl(url) { try { parseInternalUrl(url); return true; } catch { return false; } }","tryCatchPattern":"try { return await read(url) } catch (e) { if (e instanceof ToolError && !('Invalid selector' in e.message)) { /* log and rebuild URL from parts */ } throw e; }","preventionTips":["Build internal URLs from a helper that joins scheme/host/path safely","Escape colons in namespaced skill hosts per convention","Round-trip URLs through parseInternalUrl during construction"],"tags":["url","parse-error","read-tool"],"backgroundTag":"malformed-url","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}