can1357/oh-my-pi · error · ToolError

Unsupported internal URL in bash command: ${url}

Error message

Unsupported internal URL in bash command: ${url}

What it means

resolveInternalUrlToPath maps internal URLs used in bash commands (skill://, attachment://, local://, plus router-backed schemes) to filesystem paths. Before dispatching on the scheme it calls extractScheme; if the token has no recognizable scheme, it throws this ToolError. This guards the bash tool from blindly passing an opaque token to scheme-specific resolvers that would fail confusingly.

Source

Thrown at packages/coding-agent/src/tools/bash-skill-urls.ts:267

/** Shell-escape a path using single quotes. */
function shellEscape(p: string): string {
	return `'${p.replace(/'/g, "'\\''")}'`;
}

async function resolveInternalUrlToPath(
	rawUrl: string,
	skills: readonly Skill[],
	attachments: readonly ImageAttachmentEntry[],
	internalRouter?: InternalUrlResolver,
	localOptions?: LocalProtocolOptions,
	ensureLocalParentDirs?: boolean,
	cwd?: string,
	sessionFile?: string,
): Promise<string> {
	const url = normalizeLocalScheme(rawUrl);
	const scheme = extractScheme(url);
	if (!scheme) {
		throw new ToolError(`Unsupported internal URL in bash command: ${url}`);
	}

	if (scheme === "skill") {
		return resolveSkillUrlToPath(url, skills);
	}

	if (scheme === "attachment") {
		const attachment = attachments.find(entry => entry.uri === url);
		if (!attachment) {
			throw new ToolError(`Unknown attachment URL in bash command: ${url}`);
		}
		return path.resolve(attachment.sourcePath);
	}

	if (scheme === "local") {
		if (!localOptions) {
			throw new ToolError(
				"Cannot resolve local:// URL in bash command: local protocol options are unavailable for this session.",

View on GitHub (pinned to 9690622007)

Solutions

  1. Check the URL string in the failing bash command and add the missing '://' scheme separator (e.g. 'skill://name/path' not 'skill:/name/path').
  2. Use a scheme the tool understands: skill, attachment, local, or one registered with the session's internal URL router.
  3. If generating URLs programmatically, run them through the same normalizeLocalScheme/extractScheme validation before embedding in the command.
  4. Replace the internal URL with a direct filesystem path if no internal scheme applies.

Example fix

// before
const cmd = `cat skill:/pdf-guide/SKILL.md`;
// after
const cmd = `cat skill://pdf-guide/SKILL.md`;
Defensive patterns

Strategy: validation

Validate before calling

function isInternalUrl(u) { return /^[a-z][a-z0-9+.-]*:\/\//i.test(u); }
if (!isInternalUrl(rawUrl)) throw new Error(`URL needs a scheme: ${rawUrl}`);

Type guard

const hasScheme = (u: string): u is `${string}://${string}` => /^[a-z][a-z0-9+.-]*:\/\//i.test(u);

Try / catch

try { await expandInternalUrls(cmd, ctx); } catch (e) { if (e instanceof ToolError && /Unsupported internal URL/.test(e.message)) fixScheme(e); else throw e; }

Prevention

When it happens

Trigger: expandInternalUrls found a token that looks like an internal URL reference in a bash command, but after normalizeLocalScheme the string has no scheme (no '<scheme>://' prefix), e.g. a bare 'skill/foo.md' without the 'skill://' prefix, a typo'd scheme separator like 'skill:/path', or an empty/malformed URI passed where an internal URL is expected.

Common situations: Hand-written bash commands referencing internal resources with missing or malformed scheme syntax; templates or prompt text that dropped the '://' when interpolating URIs; copying a path from docs and omitting the scheme prefix.

Related errors


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