{"record":{"id":"5a014c9b9176f799","repo":"Yeachan-Heo/oh-my-codex","slug":"manifest-invalid-url","errorCode":"manifest_invalid_url","errorMessage":"[native-assets] manifest_invalid_url: ${asset.download_url}","messagePattern":"\\[native-assets\\] manifest_invalid_url: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/native-assets/policy.ts","lineNumber":183,"sourceCode":"    if (binaryPath !== asset.binary_path || binaryPath.split('/').at(-1) !== expectedBinaryPath) {\n      throw policyError('manifest_binary_basename_mismatch', asset.binary_path);\n    }\n\n    const key = nativeReleaseAssetLogicalKey(asset);\n    if (logicalKeys.has(key)) throw policyError('manifest_duplicate_logical_key', asset.archive);\n    logicalKeys.add(key);\n    const basename = nativeReleaseAssetBasename(asset);\n    if (asset.archive !== basename || !nativeArchiveSuffix(basename)) {\n      throw policyError('manifest_archive_invalid', asset.archive);\n    }\n    if (archiveHintMismatch(asset, basename)) throw policyError('manifest_archive_hint_mismatch', basename);\n    if (basenames.has(basename)) throw policyError('manifest_duplicate_archive_basename', basename);\n    basenames.add(basename);\n    let downloadUrl: URL;\n    try {\n      downloadUrl = new URL(asset.download_url);\n    } catch {\n      throw policyError('manifest_invalid_url', asset.download_url);\n    }\n    if ((downloadUrl.protocol !== 'https:' && downloadUrl.protocol !== 'http:')\n      || downloadUrl.pathname.split('/').at(-1) !== basename) {\n      throw policyError('manifest_url_basename_mismatch', asset.download_url);\n    }\n  }\n}\n","sourceCodeStart":165,"sourceCodeEnd":191,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/native-assets/policy.ts#L165-L191","documentation":"asset.download_url could not be parsed as a URL. The validator requires an absolute, parseable URL for each asset before checking protocol and basename.","triggerScenarios":"download_url is undefined, empty, a relative path like '/releases/foo.tar.zst', or otherwise rejected by the URL constructor.","commonSituations":"Template placeholders left unfilled (e.g. ${VERSION}), or a base-URL concatenation bug producing a relative string.","solutions":["Use a fully qualified absolute URL including scheme and host","Check for unfilled template variables in generated manifests","Add a unit test asserting every download_url parses"],"exampleFix":"// before\n\"download_url\": \"releases/v1/omxd-linux-x64.tar.zst\"\n// after\n\"download_url\": \"https://github.com/acme/omx/releases/download/v1/omxd-linux-x64.tar.zst\"","handlingStrategy":"validation","validationCode":"const ok = assets.every((a) => { try { new URL(a.download_url); return true; } catch { return false; } });","typeGuard":"function isParseableDownloadUrl(a: NativeAsset): boolean { try { new URL(a.download_url); return true; } catch { return false; } }","tryCatchPattern":null,"preventionTips":["Fail manifest generation if any URL fails new URL()","Check for unfilled template placeholders"],"tags":["native-assets","manifest","url-validation"],"backgroundTag":"invalid-url-in-config","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}