{"record":{"id":"79ccf0c5fbc4f07c","repo":"Yeachan-Heo/oh-my-codex","slug":"native-assets-unable-to-resolve-github-repositor","errorCode":null,"errorMessage":"[native-assets] unable to resolve GitHub repository URL for native release downloads","messagePattern":"\\[native-assets\\] unable to resolve GitHub repository URL for native release downloads","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/cli/native-assets.ts","lineNumber":96,"sourceCode":"function repositoryHttpBase(repository: { url?: string } | string | undefined): string | undefined {\n  const raw = typeof repository === 'string' ? repository : repository?.url;\n  if (!raw?.trim()) return undefined;\n  const trimmed = raw.trim().replace(/^git\\+/, '').replace(/\\.git$/, '');\n  if (trimmed.startsWith('https://github.com/')) return trimmed;\n  if (trimmed.startsWith('http://github.com/')) return trimmed.replace(/^http:/, 'https:');\n  return undefined;\n}\n\nexport async function resolveNativeReleaseBaseUrl(\n  packageRoot = getPackageRoot(),\n  version?: string,\n  env: NodeJS.ProcessEnv = process.env,\n): Promise<string> {\n  const override = env[NATIVE_RELEASE_BASE_URL_ENV]?.trim();\n  if (override) return override.replace(/\\/$/, '');\n  const pkg = await readPackageJson(packageRoot);\n  const repo = repositoryHttpBase(pkg.repository);\n  if (!repo) throw new Error('[native-assets] unable to resolve GitHub repository URL for native release downloads');\n  const resolvedVersion = version ?? await getPackageVersion(packageRoot);\n  return `${repo}/releases/download/v${resolvedVersion}`;\n}\n\nexport async function resolveNativeManifestUrl(\n  packageRoot = getPackageRoot(),\n  version?: string,\n  env: NodeJS.ProcessEnv = process.env,\n): Promise<string> {\n  const override = env[NATIVE_MANIFEST_URL_ENV]?.trim();\n  if (override) return override;\n  const baseUrl = await resolveNativeReleaseBaseUrl(packageRoot, version, env);\n  return `${baseUrl}/native-release-manifest.json`;\n}\n\nexport function resolveNativeCacheRoot(env: NodeJS.ProcessEnv = process.env): string {\n  const override = env[NATIVE_CACHE_DIR_ENV]?.trim();\n  if (override) return resolve(override);","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/cli/native-assets.ts#L78-L114","documentation":"The native-assets hydration module cannot derive a GitHub releases base URL. It first honors the NATIVE_RELEASE_BASE_URL environment override; otherwise it reads the package.json repository field and converts it to an HTTPS base (repositoryHttpBase). If that field is missing, malformed, or not a recognized GitHub URL, the release download URL cannot be constructed and hydration fails.","triggerScenarios":"Calling resolveNativeReleaseBaseUrl / hydrateNativeBinary when package.json has no repository field, a non-object repository (e.g. a string git URL it can't parse), a URL pointing at a non-GitHub host, or when repositoryHttpBase returns null for shorthand like 'user/repo' variants it doesn't support.","commonSituations":"Private forks that stripped repository metadata, workspaces publishing from a dist folder without package.json, tarball installs where package.json was pruned, or companies mirroring releases off-GitHub without setting NATIVE_RELEASE_BASE_URL.","solutions":["Set NATIVE_RELEASE_BASE_URL to your releases base (e.g. https://github.com/acme/omx/releases/download) since env override wins.","Fix package.json: \"repository\": {\"type\":\"git\",\"url\":\"https://github.com/owner/repo.git\"}.","If you mirror assets internally, point the env var at your internal mirror's base URL and pre-hydrate the cache in CI."],"exampleFix":"// before\n\"repository\": \"git+ssh://git@internal-git.corp/omx.git\"\n// after\n\"repository\": { \"type\": \"git\", \"url\": \"https://github.com/owner/omx.git\" }\n// or: export NATIVE_RELEASE_BASE_URL=https://github.com/owner/omx/releases/download","handlingStrategy":"validation","validationCode":"import { readFileSync } from 'node:fs';\nfunction hasRepositoryUrl(pkgPath = 'package.json'): boolean {\n  try {\n    const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));\n    const repo = pkg.repository;\n    const url = typeof repo === 'string' ? repo : repo?.url ?? '';\n    return /^https?:\\/\\/github\\.com\\//.test(url.replace(/^git\\+/, '').replace(/\\.git$/, ''))\n      || Boolean(process.env.NATIVE_RELEASE_BASE_URL);\n  } catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"try { await hydrateNativeBinary(); } catch (e) { if (/unable to resolve GitHub repository URL/.test(String(e))) { /* set NATIVE_RELEASE_BASE_URL or fix package.json, then retry */ } throw e; }","preventionTips":["Set NATIVE_RELEASE_BASE_URL in CI","Keep a valid GitHub repository field in package.json","Snapshot-test package.json metadata before publishing"],"tags":["native-assets","package-json","repository-url","github-releases"],"backgroundTag":"package-metadata-missing","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}