{"record":{"id":"8a5a6ebcf4fc3104","repo":"can1357/oh-my-pi","slug":"artifact-id-not-found-available-availablest","errorCode":null,"errorMessage":"Artifact ${id} not found. Available: ${availableStr}","messagePattern":"Artifact (.+?) not found\\. Available: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/internal-urls/artifact-protocol.ts","lineNumber":88,"sourceCode":"\t\tconst match = files.find(f => f.startsWith(`${id}.`));\n\t\tif (match) {\n\t\t\tfoundPath = path.join(dir, match);\n\t\t\tbreak;\n\t\t}\n\t\tfor (const f of files) {\n\t\t\tconst m = f.match(/^(\\d+)\\./);\n\t\t\tif (m) availableIds.add(m[1]);\n\t\t}\n\t}\n\n\tif (!anyDirExists) {\n\t\tthrow new Error(\"No artifacts directory found\");\n\t}\n\n\tif (!foundPath) {\n\t\tconst sorted = [...availableIds].sort((a, b) => Number(a) - Number(b));\n\t\tconst availableStr = sorted.length > 0 ? sorted.join(\", \") : \"none\";\n\t\tthrow new Error(`Artifact ${id} not found. Available: ${availableStr}`);\n\t}\n\n\tconst stat = await Bun.file(foundPath).stat();\n\tif (stat.isDirectory()) {\n\t\tthrow new Error(`Artifact ${id} resolved to a directory, not a file`);\n\t}\n\treturn { id, path: foundPath, size: stat.size };\n}\n\nexport class ArtifactProtocolHandler implements ProtocolHandler {\n\treadonly scheme = \"artifact\";\n\treadonly immutable = true;\n\n\tasync resolve(url: InternalUrl, context?: ResolveContext): Promise<InternalResource> {\n\t\tconst artifact = await resolveArtifactFile(url, context);\n\n\t\t// Path-only callers (search/grep, bash URL expansion) never touch the\n\t\t// artifact bytes. Return the resource shape so those flows keep working","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/internal-urls/artifact-protocol.ts#L70-L106","documentation":"resolveArtifactFile scans the session artifacts directory for a file whose id matches the requested artifact id. If no file matches after normalizing ids, it throws with the sorted list of ids that DO exist (or 'none') so the caller can pick a valid one. It exists to turn a bad artifact:// URL into an actionable message instead of a silent null.","triggerScenarios":"Calling artifact://<id> (via resolveArtifactFile/artifact) with an id that is not in the artifacts directory — e.g. a stale id from a previous session, a typo, or referencing artifacts of a different session whose directory is being scanned.","commonSituations":"Agent referenced an artifact id from an old transcript after artifacts were cleaned up; user hand-wrote an artifact:// URL guessing the id; artifacts directory was pruned between tool call and read.","solutions":["Use the 'Available: ...' ids listed in the message and retry with one of those ids","List all artifacts first (iterate the artifacts directory or the artifact:// listing) to confirm valid ids","If the artifact should exist, check you are pointing at the correct session's artifacts directory"],"exampleFix":"// before\nconst doc = await resolve(`artifact://1042:1-200`)\n// after\nconst doc = await resolve(`artifact://1041:1-200`) // 1041 listed as available","handlingStrategy":"fallback","validationCode":"import { readdir } from 'node:fs/promises'\nconst ids = (await readdir(artifactsDir)).map(f => f.replace(/\\.\\w+$/, ''))\nif (!ids.includes(wantedId)) throw new Error(`artifact id ${wantedId} not in [${ids.join(', ')}]`)","typeGuard":null,"tryCatchPattern":"try {\n  const art = await resolve(`artifact://${id}`)\n} catch (err) {\n  const avail = /Available: (.+)$/.exec(String(err))?.[1]\n  if (avail && avail !== 'none') return resolve(`artifact://${avail.split(',')[0].trim()}`)\n  throw err\n}","preventionTips":["Capture artifact ids from the tool result that created them instead of guessing","List available artifact ids before resolving","Keep artifact references together with the session that produced them"],"tags":["artifact","not-found","internal-url"],"backgroundTag":"resource-id-not-found","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}