can1357/oh-my-pi · error · ToolError

Could not resolve image attachment '${readPath}'. Available

Error message

Could not resolve image attachment '${readPath}'. Available attachment URIs: ${availableUris}. Use one of the listed attachment URIs, or attach an image first when none are available.

What it means

Reads of image attachment URIs (matching IMAGE_ATTACHMENT_URI_REGEX) are resolved against the session's registered image attachments. If no attachment's uri equals the requested readPath, the tool throws a ToolError listing every available attachment URI (or 'none') and instructs the caller to use one of them or attach an image first.

Source

Thrown at packages/coding-agent/src/tools/read.ts:1097

	async #executeInner(
		_toolCallId: string,
		params: ReadParams,
		signal?: AbortSignal,
		_onUpdate?: AgentToolUpdateCallback<ReadToolDetails>,
		_toolContext?: AgentToolContext,
	): Promise<AgentToolResult<ReadToolDetails>> {
		let { path: readPath } = params;
		if (readPath.startsWith("file://")) {
			readPath = expandPath(readPath);
		}

		if (IMAGE_ATTACHMENT_URI_REGEX.test(readPath)) {
			const attachments = this.session.getImageAttachments?.() ?? [];
			const attachment = attachments.find(entry => entry.uri === readPath);
			if (!attachment) {
				const availableUris = attachments.map(entry => entry.uri).join(", ") || "none";
				throw new ToolError(
					`Could not resolve image attachment '${readPath}'. Available attachment URIs: ${availableUris}. Use one of the listed attachment URIs, or attach an image first when none are available.`,
				);
			}
			readPath = attachment.sourcePath;
		}

		const conflictUri = parseConflictUri(readPath);
		if (conflictUri) {
			if (conflictUri.id === "*") {
				throw new ToolError(
					"Reading `conflict://*` is not supported — wildcards are write-only. Use the `<path>:conflicts` read selector for the full list of conflicts in a file, or read `conflict://<N>` to inspect a single block.",
				);
			}
			return this.#readConflictRegion(conflictUri.id, conflictUri.scope);
		}
		const displayMode = resolveFileDisplayMode(this.session);

		const parsedUrlTarget = parseReadUrlTarget(readPath);

View on GitHub (pinned to 9690622007)

Solutions

  1. Copy the URI exactly from the 'Available attachment URIs' list in the message.
  2. If the list is 'none', attach the image to the session first (drag-and-drop/paste into the client) before reading.
  3. Re-attach the image if the session was restarted and use the new URI.
  4. Fall back to reading the original file from disk by path if it exists locally.

Example fix

// before
read('attachment://img-42') // stale id
// after
read('attachment://img-7f3a') // URI copied from the available list
Defensive patterns

Strategy: validation

Validate before calling

const attachments = session.getImageAttachments?.() ?? [];
const uris = new Set(attachments.map(a => a.uri));
if (!uris.has(attachmentUri)) {
  // fall back to the original file on disk, or attach first
  throw new Error(`Unknown attachment ${attachmentUri}; known: ${[...uris].join(', ') || 'none'}`);
}

Type guard

function isKnownAttachment(uri: string, session: Session): boolean {
  return (session.getImageAttachments?.() ?? []).some(a => a.uri === uri);
}

Try / catch

try {
  return await readTool.execute({ path: uri });
} catch (e) {
  if (e instanceof ToolError && e.message.startsWith('Could not resolve image attachment')) {
    const available = e.message.match(/Available attachment URIs: ([^.]*)/)?.[1] ?? 'none';
    const first = available.split(', ')[0];
    return first && first !== 'none' ? readTool.execute({ path: first }) : null;
  }
  throw e;
}

Prevention

When it happens

Trigger: Reading 'attachment://<id>' (or similar) with a stale/typo'd URI; the attachment was dropped from session history; a new session with no attachments while the model replays an old URI.

Common situations: Model hallucinating or misremembering an attachment URI; referencing an image attached in a previous session/turn that was garbage-collected; whitespace or case mismatch in the URI.

Related errors


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