can1357/oh-my-pi · error · Error

Security finding path is outside the immutable scan scope: $

Error message

Security finding path is outside the immutable scan scope: ${input.path}

What it means

toLocation checks the normalized finding path against the immutable scan scope recorded in the plan (target include/exclude globs). Findings may only reference files inside the paths that were actually scanned; anything outside is rejected so published results cannot claim issues in unscanned or out-of-scope locations.

Source

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

	const segments = normalized.split("/");
	if (
		!normalized ||
		normalized.startsWith("/") ||
		/^[a-zA-Z]:\//.test(normalized) ||
		segments.some(segment => segment === "..")
	) {
		throw new Error(`Security finding paths must be repository-relative: ${input}`);
	}
	return normalized;
}

function toLocation(
	input: SecurityPublishParams["findings"][number]["locations"][number],
	plan: SecurityScanPlan,
): SecurityLocation {
	const normalizedPath = normalizePublishedPath(input.path);
	if (!pathMatchesSecurityScope(normalizedPath, plan.target.includePaths, plan.target.excludePaths)) {
		throw new Error(`Security finding path is outside the immutable scan scope: ${input.path}`);
	}
	const location: SecurityLocation = {
		path: normalizedPath,
		startLine: input.start_line,
	};
	if (input.end_line !== undefined) location.endLine = input.end_line;
	if (input.start_column !== undefined) location.startColumn = input.start_column;
	if (input.end_column !== undefined) location.endColumn = input.end_column;
	if (input.role !== undefined) location.role = input.role;
	return location;
}

function coverageMode(plan: SecurityScanPlan): SecurityCoverage["mode"] {
	switch (plan.target.kind) {
		case "ref_diff":
			return "diff";
		case "working_tree":
			return "working_tree";

View on GitHub (pinned to 9690622007)

Solutions

  1. Move or drop findings whose paths fall outside the plan's target include globs
  2. Re-run the scan with includePaths covering the file the finding refers to
  3. Verify the path does not hit an excludePaths glob (vendor, dist, node_modules)
  4. Re-publish against the plan that was actually used for the scan

Example fix

// before (plan includes only 'src/**')
findings: [{ ..., locations: [{ path: "docs/notes.md", start_line: 1 }] }]
// after
findings: [{ ..., locations: [{ path: "src/app.ts", start_line: 1 }] }]
Defensive patterns

Strategy: validation

Validate before calling

if (!pathMatchesSecurityScope(rel, plan.target.includePaths, plan.target.excludePaths)) throw new Error("out of scope");

Type guard

null

Try / catch

try { await publish(params); } catch (e) { if (String(e.message).includes("outside the immutable scan scope")) { /* filter findings or rescan */ } else throw e; }

Prevention

When it happens

Trigger: Calling the security publish tool with a finding whose path, while repository-relative, does not match plan.target.includePaths or is matched by plan.target.excludePaths — e.g. scanning src/ but publishing a finding in docs/, or the plan's includes changed between scan and publish.

Common situations: The LLM invents locations outside the scanned directory, publishing findings from a previous scan against a new plan, typos in include globs (e.g. 'src' vs 'source'), or intentionally excluded vendor/node_modules paths.

Related errors


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