can1357/oh-my-pi · info

aborted

Error message

aborted

What it means

IssueProtocolHandler.resolve (packages/coding-agent/src/internal-urls/issue-pr-protocol.ts:518) checks the caller-supplied AbortSignal before doing any work and throws a plain Error('aborted') if context.signal.aborted is already true. It is the handler's cooperative-cancellation contract: a resolve() call made with an already-cancelled signal refuses to start. It is an Error, not a DOMException, so callers must match on message rather than error name.

Source

Thrown at packages/coding-agent/src/internal-urls/issue-pr-protocol.ts:518

	return {
		url: url.href,
		content,
		contentType: "text/markdown",
		size: Buffer.byteLength(content, "utf-8"),
		notes: [freshness, `File listing for pr://${repo}/${parsed.number}`],
	};
}

/**
 * Handler for `issue://` URLs.
 */
export class IssueProtocolHandler implements ProtocolHandler {
	readonly scheme = "issue";
	readonly immutable = true;

	async resolve(url: InternalUrl, context?: ResolveContext): Promise<InternalResource> {
		if (context?.signal?.aborted) {
			throw new Error("aborted");
		}
		const parsed = parseUrl(url, "issue");
		if (parsed.kind === "list") {
			try {
				return await fetchAndRenderList("issue", parsed, url, context);
			} catch (err) {
				const message = err instanceof Error ? err.message : String(err);
				throw new Error(`issue:// listing failed: ${message}`);
			}
		}
		// parseUrl already rejects `issue://.../diff`; this guard is a belt-and-
		// suspenders catch in case the union grows.
		if (parsed.kind !== "single") {
			throw new Error(`Invalid issue:// URL: unexpected variant '${parsed.kind}'`);
		}
		try {
			const lookup = await getOrFetchIssue({
				cwd: resolveCwd(context),

View on GitHub (pinned to 9690622007)

Solutions

  1. Treat this as a benign cancellation, not a failure: catch it and skip/ignore the resolution result.
  2. Check signal.aborted before calling resolve() and skip the call entirely when it is already true.
  3. Create a fresh AbortController per resolution if you intend the lookup to proceed despite an earlier cancellation elsewhere.
  4. If you need typed cancellation, wrap the throw site (or catch site) to convert it into a DOMException('aborted','AbortError').

Example fix

// before
const resource = await handler.resolve(url, { signal: sharedController.signal });
// after
if (sharedController.signal.aborted) return; // skip aborted lookups
const resource = await handler.resolve(url, { signal: sharedController.signal });
Defensive patterns

Strategy: try-catch

Validate before calling

// Skip the call entirely when already cancelled:
if (context?.signal?.aborted) return null; // do not invoke resolve()

Type guard

function isAbortError(err: unknown): err is Error {
  return err instanceof Error && (
    err.message === "aborted" || err.name === "AbortError"
  );
}

Try / catch

try {
  const res = await issueHandler.resolve(url, { signal });
} catch (err) {
  if (err instanceof Error && err.message === "aborted") return; // benign cancellation
  throw err;
}

Prevention

When it happens

Trigger: Calling issueProtocolHandler.resolve(url, { signal }) where the passed AbortSignal was already aborted (e.g. AbortController.abort() fired before or while enqueueing the resolution), such as when a chat turn is cancelled and pending internal-URL lookups are flushed with aborted signals.

Common situations: User cancels/clears a session turn in the TUI while issue:// links are queued for resolution; a timeout aborts the controller before the handler runs; a race between abort and the async queue dispatch.

Related errors


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