can1357/oh-my-pi · error

Codex Security bundle locations must be repository-relative

Error message

Codex Security bundle locations must be repository-relative: ${value}

What it means

Codex Security bundle finding locations must be repository-relative paths. importedLocationPath normalizes each location value and rejects empty strings, absolute POSIX paths, drive-letter absolute paths (C:/...), and any path segment equal to '..', because findings must only ever point inside the imported repository bundle.

Solutions

  1. Rewrite the finding's location paths in findings.json to be relative to the repository root (e.g. "src/a.ts")
  2. Remove any ".." segments by resolving the path to its repository-relative form before importing
  3. Drop or blank-to-nullify locations for findings that genuinely have no file association if the schema allows

Example fix

// before (findings.json)
"location": "/Users/alice/repo/src/auth.ts"
// after
"location": "src/auth.ts"
Defensive patterns

Strategy: validation

Validate before calling

for (const f of findingsDocument.findings) {
  for (const loc of f.locations ?? []) {
    const p = loc.path ?? "";
    if (!p || p.startsWith("/") || /^[a-zA-Z]:\//.test(p) || p.split("/").includes("..")) {
      throw new Error(`Location must be repository-relative: ${p}`);
    }
  }
}

Type guard

function isRepoRelativePath(value: unknown): value is string {
  return typeof value === "string" && value.length > 0 &&
    !value.startsWith("/") && !/^[a-zA-Z]:\//.test(value) &&
    !value.split("/").includes("..");
}

Try / catch

try {
  const bundle = await importCodexSecurityBundle(dir);
} catch (err) {
  if (err instanceof Error && err.message.includes("must be repository-relative")) {
    console.error(`Bad location path in bundle: ${err.message}`); // fix findings.json paths and retry
  } else throw err;
}

Prevention

When it happens

Trigger: A findings.json entry has a location path that is absolute (e.g. "/home/user/repo/src/a.ts" or "C:/repo/a.ts"), contains a ".." segment, or is empty/whitespace when a Codex Security bundle is imported.

Common situations: Hand-edited or tool-generated findings.json with machine-absolute paths; paths written on a different machine with drive letters; path traversal segments left in by a generator; empty location fields for findings without a file.

Related errors


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

Appendix: source

Thrown at packages/coding-agent/src/security/importers/codex-security.ts:119

}

async function readJson<T>(filePath: string): Promise<T> {
	return JSON.parse(await Bun.file(filePath).text()) as T;
}

function stringArray(value: unknown): string[] {
	return Array.isArray(value) ? value.filter((item): item is string => typeof item === "string") : [];
}

function importedLocationPath(value: string): string {
	const normalized = value.replaceAll("\\", "/").replace(/^\.\//, "");
	if (
		!normalized ||
		normalized.startsWith("/") ||
		/^[a-zA-Z]:\//.test(normalized) ||
		normalized.split("/").includes("..")
	) {
		throw new Error(`Codex Security bundle locations must be repository-relative: ${value}`);
	}
	return normalized;
}

function locationsForFinding(finding: CodexFinding): SecurityLocation[] {
	const locations: SecurityLocation[] = [];
	for (const location of finding.locations ?? []) {
		if (typeof location.path !== "string" || typeof location.startLine !== "number") continue;
		const normalized: SecurityLocation = {
			path: importedLocationPath(location.path),
			startLine: location.startLine,
		};
		if (location.endLine !== undefined) normalized.endLine = location.endLine;
		if (location.role !== undefined) normalized.role = location.role;
		locations.push(normalized);
	}
	return locations.length > 0 ? locations : [{ path: "unknown", startLine: 1, role: "unknown" }];
}

View on GitHub (pinned to 9690622007)