can1357/oh-my-pi · error · Error

Security scan project key ${bundle.scan.projectKey} does not

Error message

Security scan project key ${bundle.scan.projectKey} does not match ${this.#projectKey}

What it means

#putBundleUnlocked() enforces that a scan bundle's projectKey matches the key derived from the repository root this SecurityStore was opened for. projectKey is computed by SecurityStore.open() via encodeSecurityProjectKey(realpath(repositoryRoot)). Writing a bundle stamped with another project's key would cross-contaminate stores, so it is rejected.

Source

Thrown at packages/coding-agent/src/security/store.ts:243

			throw new Error(`Invalid security store scan index at ${this.#indexPath()}`);
		}
		if (
			value.planIds !== undefined &&
			(!Array.isArray(value.planIds) || !value.planIds.every(id => typeof id === "string"))
		) {
			throw new Error(`Invalid security store plan index at ${this.#indexPath()}`);
		}
		return { ...value, planIds: value.planIds ?? [] } as SecurityStoreIndex;
	}

	async #writeIndex(index: SecurityStoreIndex): Promise<void> {
		await writeSecurityFileAtomic(this.#indexPath(), `${JSON.stringify(index, null, 2)}\n`);
	}

	async #putBundleUnlocked(input: SecurityScanBundle): Promise<void> {
		const bundle = parseSecurityScanBundle(input);
		if (bundle.scan.projectKey !== this.#projectKey) {
			throw new Error(`Security scan project key ${bundle.scan.projectKey} does not match ${this.#projectKey}`);
		}
		const scanDirectory = this.#scanDirectory(bundle.scan.id);
		await ensurePrivateDirectory(scanDirectory);
		await writeSecurityFileAtomic(
			path.join(scanDirectory, "findings.json"),
			`${JSON.stringify(bundle.findings, null, 2)}\n`,
		);
		if (bundle.report !== undefined) {
			await writeSecurityFileAtomic(path.join(scanDirectory, "report.md"), bundle.report);
		} else {
			await fs.rm(path.join(scanDirectory, "report.md"), { force: true });
		}
		if (bundle.sarif !== undefined) {
			await writeSecurityFileAtomic(
				path.join(scanDirectory, "results.sarif"),
				`${JSON.stringify(bundle.sarif, null, 2)}\n`,
			);
		} else {

View on GitHub (pinned to 9690622007)

Solutions

  1. Open the SecurityStore for the repository the scan actually ran against (matching canonical realpath) so projectKeys align.
  2. Re-emit the bundle with scan.projectKey set to store.projectKey only if the scan genuinely belongs to this repository and the old key is stale.
  3. Use writeSecurityBundleToDirectory() / getBundle() on the original store instead of copying bundles across store instances.
  4. Log both keys in the message and compare with the original scan store's projectKey to confirm which side is stale before editing anything.

Example fix

// before
const storeA = await SecurityStore.open('/repos/app');
await storeA.putBundle(bundleFromOtherRepo); // scan.projectKey = key('/repos/app-copy')
// after
const storeB = await SecurityStore.open('/repos/app-copy');
await storeB.putBundle(bundleFromOtherRepo); // open the store for the scan's own repo
Defensive patterns

Strategy: validation

Validate before calling

const store = await SecurityStore.open(repoRoot);
if (bundle.scan.projectKey !== store.projectKey) {
  throw new Error(`bundle belongs to ${bundle.scan.projectKey}, not ${store.projectKey}`);
}

Type guard

function matchesStore(bundle: SecurityScanBundle, store: SecurityStore): boolean {
  return bundle.scan.projectKey === store.projectKey;
}

Try / catch

try {
  await store.putBundle(bundle);
} catch (err) {
  if (err instanceof Error && err.message.includes('does not match')) {
    // open the store for the bundle's own repository instead
  } else throw err;
}

Prevention

When it happens

Trigger: Calling putBundle(), updateDisposition(), or updateValidation() with a bundle whose scan.projectKey differs from store.projectKey — e.g. the bundle was produced in a different checkout/clone or moved repository, or the store was opened with a different stateRoot against a moved repo whose canonical path changed.

Common situations: Copy-pasting scan bundles between machines or repos; a repository cloned to a new path so its canonical root (and thus projectKey) changed; opening the store via openForCwd() in a subdirectory of a different VCS root than where the scan ran; renaming/moving the repo between scan creation and store write.

Related errors


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