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
- Open the SecurityStore for the repository the scan actually ran against (matching canonical realpath) so projectKeys align.
- 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.
- Use writeSecurityBundleToDirectory() / getBundle() on the original store instead of copying bundles across store instances.
- 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
- Always write bundles to the store opened from the same repositoryRoot that produced them.
- Log store.projectKey and scan.projectKey together when moving scans between environments.
- Re-derive project keys after repositories are moved or cloned; never assume keys are portable.
- Use openForCwd() inside the scan's working tree so the canonical root matches.
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
- Invalid security store plan index at ${this.#indexPath()}
- Security plan repository ${plan.repositoryRoot} does not mat
- Invalid findings list for ${scanId}
- Unknown security scan: ${scanId}
- Unknown security finding: ${findingId}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/0ea3301392e42014.
Report an issue: GitHub.