can1357/oh-my-pi · error · ToolError

path must be repository-relative

Error message

path must be repository-relative

What it means

executeFileRead reads a file's contents from a GitHub repository via the gh-backed API. The `path` parameter must be relative to the repository root; an absolute path (leading '/') would produce a malformed API path, so it is rejected up front with a ToolError.

Source

Thrown at packages/coding-agent/src/tools/gh.ts:267

					return executeSearchCommits(this.session, params, signal);
				case "search_repos":
					return executeSearchRepos(this.session, params, signal);
				case "run_watch":
					return executeRunWatch(this.session, this.name, params, signal, onUpdate);
			}
		});
	}
}

async function executeFileRead(
	session: ToolSession,
	params: GithubInput,
	signal: AbortSignal | undefined,
): Promise<AgentToolResult<GhToolDetails>> {
	const repo = await resolveGitHubRepo(session.cwd, normalizeOptionalString(params.repo), undefined, signal);
	const filePath = requireNonEmpty(normalizeOptionalString(params.path), "path");
	if (filePath.startsWith("/")) {
		throw new ToolError("path must be repository-relative");
	}
	const branch = normalizeOptionalString(params.branch);
	const endpointPath = filePath
		.split("/")
		.map(segment => encodeURIComponent(segment))
		.join("/");
	const ref = parseRepoRef(repo);
	const args = [
		"api",
		...ghApiHostArgs(ref),
		`/repos/${ref.slug}/contents/${endpointPath}`,
		"--method",
		"GET",
		"-H",
		"Accept: application/vnd.github+json",
		"-H",
		"Accept-Encoding: identity",
	];

View on GitHub (pinned to 9690622007)

Solutions

  1. Remove the leading slash: 'src/index.ts' instead of '/src/index.ts'
  2. Strip the repo-root prefix if the input came from a local absolute path
  3. Normalize with something like path.replace(/^\/+/, '') before invoking

Example fix

// before
await executeFileRead({ path: "/src/index.ts" });
// after
await executeFileRead({ path: "src/index.ts" });
Defensive patterns

Strategy: validation

Validate before calling

const rel = normalizeOptionalString(params.path)?.replace(/^\\/+/, "");
if (!rel) throw new Error("path required");
await executeFileRead({ ...params, path: rel });

Type guard

const isRepoRelativePath = (p: string): boolean => p.length > 0 && !p.startsWith("/");

Try / catch

try {
  await gh.readFile({ path });
} catch (err) {
  if (err instanceof ToolError && err.message === "path must be repository-relative") {
    path = path.replace(/^\\/+/, "");
    // retry once with the corrected path
  } else throw err;
}

Prevention

When it happens

Trigger: Calling the github file-read op with path: '/src/index.ts' or path: '/README.md' — any string whose first character is '/'.

Common situations: Agents converting local absolute paths directly to GitHub paths; users pasting URLs where the leading slash of the path segment survived; code that does path.join('/', file).

Related errors


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