{"record":{"id":"999c6b8c6ac515e4","repo":"midudev/autoskills","slug":"download-failed-for-normalizedrel-errors-join","errorCode":null,"errorMessage":"download failed for ${normalizedRel}: ${errors.join(\"; \")}","messagePattern":"download failed for (.+?): (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/autoskills/installer.ts","lineNumber":321,"sourceCode":"        );\n      }\n      errors.push(`${res.status} ${res.statusText} from ${baseUrl}`);\n      opts.onTrace?.(`miss ${normalizedRel}: ${res.status} ${res.statusText} from ${baseUrl}`);\n      continue;\n    }\n\n    const buf = Buffer.from(await res.arrayBuffer());\n    const actual = sha256Buffer(buf);\n    if (actual !== expected) {\n      errors.push(`hash mismatch from ${baseUrl}`);\n      opts.onTrace?.(`hash mismatch for ${normalizedRel} from ${baseUrl}`);\n      continue;\n    }\n    opts.onTrace?.(`downloaded ${normalizedRel} from ${url}`);\n    return { buf, url };\n  }\n\n  throw new Error(`download failed for ${normalizedRel}: ${errors.join(\"; \")}`);\n}\n\nasync function downloadRegistryEntry(\n  skillName: string,\n  entry: RegistryEntry,\n  destDir: string,\n  opts: InstallOptions,\n): Promise<void> {\n  const files = [];\n  for (const rel of entry.files) {\n    files.push({\n      rel: normalizeRegistryRelPath(rel),\n      ...(await downloadRegistryFile(skillName, entry, rel, opts)),\n    });\n  }\n\n  const bundleHash = createHash(\"sha256\")\n    .update(","sourceCodeStart":303,"sourceCodeEnd":339,"githubUrl":"https://github.com/midudev/autoskills/blob/0ec725320d2137253ab2e68e7ba8a072148e741a/packages/autoskills/installer.ts#L303-L339","documentation":"downloadRegistryFile tries each candidate registry base URL in turn; non-fatal failures are collected into an errors array and it continues to the next URL. Only after every base URL has failed does it throw this aggregated error, joining the per-URL failure reasons (HTTP status + statusText) with semicolons.","triggerScenarios":"All base URLs produced by getRegistryRawBaseUrls (configured URL, or versioned + main fallback) returned non-ok responses (or otherwise failed) for the requested skill file — e.g. 404 Not Found on every mirror because the file doesn't exist in the registry at that version or branch.","commonSituations":"Requesting a skill/file that was renamed or removed; a pinned package version whose tag does not exist on the raw host yet; a custom AUTOSKILLS_REGISTRY_BASE_URL pointing at the wrong path or a downed mirror; offline/blocked network with proxy errors surfaced per attempt.","solutions":["Read the joined per-URL reasons in the message (e.g. '404 Not Found from ...') to see the actual HTTP failure and fix accordingly.","Verify the skill name and relative path exist in the registry at your resolved version; correct the registry entry or upgrade/downgrade the autoskills version.","Check AUTOSKILLS_REGISTRY_BASE_URL / registryBaseUrl points to a valid raw base ending with the skills-registry prefix.","Fix network/proxy access to the registry host and retry; confirm the target branch/tag exists on the remote."],"exampleFix":"// before\nAUTOSKILLS_REGISTRY_BASE_URL=https://raw.githubusercontent.com/org/repo/wrong-branch/packages/autoskills/skills-registry\n// 404 from every attempt -> 'download failed for skills/foo/SKILL.md: 404 Not Found from ...'\n\n// after\nAUTOSKILLS_REGISTRY_BASE_URL=https://raw.githubusercontent.com/org/repo/main/packages/autoskills/skills-registry","handlingStrategy":"try-catch","validationCode":"// probe every candidate base URL before installing\nasync function baseOk(baseUrl) {\n  try {\n    const res = await fetch(`${baseUrl}/registry.json`);\n    return res.ok;\n  } catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await downloadRegistryEntry(name, entry, dest);\n} catch (e) {\n  if (e.message.startsWith(\"download failed for \")) {\n    const reasons = e.message.split(\"download failed for \")[1];\n    logger.error(\"All registry mirrors failed\", { reasons });\n    throw new Error(`Registry unreachable — check paths/network. Details: ${reasons}`);\n  } else throw e;\n}","preventionTips":["Verify the skill/rel path exists in the registry manifest before attempting download.","Point registryBaseUrl at a pinned version tag, not a mutable branch, for reproducible installs.","Test network/proxy access to the registry host from the target environment.","Confirm the configured base URL ends with the correct skills-registry prefix."],"tags":["network","download-failed","http","registry"],"backgroundTag":"http-error-response","analyzedSha":"0ec725320d2137253ab2e68e7ba8a072148e741a","analyzedAt":"2026-09-15T14:12:31.090Z","contentChangedAt":"2026-09-15T14:12:31.090Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}