Yeachan-Heo/oh-my-codex · error
manifest_duplicate_logical_key
manifest_duplicate_logical_key
Error message
[native-assets] manifest_duplicate_logical_key: ${asset.archive} What it means
Two assets in the manifest map to the same logical key (product/platform/target identity), meaning the same logical asset is declared twice. The validator enforces uniqueness via nativeReleaseAssetLogicalKey.
Source
Thrown at src/native-assets/policy.ts:170
}
const mapping = nativeTargetMapping(asset.target);
if (!mapping || mapping.platform !== asset.platform || mapping.arch !== asset.arch
|| (mapping.platform === 'linux' ? asset.libc !== mapping.libc : asset.libc !== undefined)) {
throw policyError('manifest_target_mismatch', asset.target || asset.archive);
}
const expectedBinary = nativeProductBinaryName(asset.product);
const expectedBinaryPath = nativeProductBinaryPath(asset.product, asset.platform);
if (!expectedBinary || !expectedBinaryPath || asset.binary !== expectedBinary) {
throw policyError('manifest_binary_product_mismatch', asset.binary);
}
const binaryPath = normalizeNativeArchivePath(asset.binary_path, 'file');
if (binaryPath !== asset.binary_path || binaryPath.split('/').at(-1) !== expectedBinaryPath) {
throw policyError('manifest_binary_basename_mismatch', asset.binary_path);
}
const key = nativeReleaseAssetLogicalKey(asset);
if (logicalKeys.has(key)) throw policyError('manifest_duplicate_logical_key', asset.archive);
logicalKeys.add(key);
const basename = nativeReleaseAssetBasename(asset);
if (asset.archive !== basename || !nativeArchiveSuffix(basename)) {
throw policyError('manifest_archive_invalid', asset.archive);
}
if (archiveHintMismatch(asset, basename)) throw policyError('manifest_archive_hint_mismatch', basename);
if (basenames.has(basename)) throw policyError('manifest_duplicate_archive_basename', basename);
basenames.add(basename);
let downloadUrl: URL;
try {
downloadUrl = new URL(asset.download_url);
} catch {
throw policyError('manifest_invalid_url', asset.download_url);
}
if ((downloadUrl.protocol !== 'https:' && downloadUrl.protocol !== 'http:')
|| downloadUrl.pathname.split('/').at(-1) !== basename) {
throw policyError('manifest_url_basename_mismatch', asset.download_url);
}View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Remove the duplicate entry so each logical asset appears once
- If you need multiple archives per platform, restructure to distinct product/target values
- Diff the manifest against the last known-good version to spot the copied block
Example fix
// before
[{platform:'linux-x64',archive:'a.tar.zst'},{platform:'linux-x64',archive:'b.tar.zst'}]
// after
[{platform:'linux-x64',archive:'a.tar.zst'},{platform:'linux-arm64',archive:'b.tar.zst'}] Defensive patterns
Strategy: validation
Validate before calling
const keys = new Set<string>();
for (const a of manifest.assets) {
const k = nativeReleaseAssetLogicalKey(a);
if (keys.has(k)) throw new Error(`duplicate logical key: ${k}`);
keys.add(k);
} Prevention
- Diff manifests before shipping
- Automate manifest generation
When it happens
Trigger: Two entries with identical product+platform (or whatever fields compose the logical key), e.g. the same linux-x64 asset listed with two different archive names.
Common situations: Copy-pasted asset blocks when adding a new platform, or a partial edit that duplicated an existing row.
Related errors
- [native-assets] failed to fetch native release manifest (${r
- [native-assets] manifest version mismatch: expected ${versio
- manifest_binary_product_mismatch
- manifest_binary_basename_mismatch
- manifest_archive_invalid
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/c2e31e050a55b22a.
Report an issue: GitHub.