midudev/autoskills · error · Error

download failed for

Error message

download failed for ${normalizedRel}: ${errors.join("; ")}

What it means

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.

Solutions

  1. Read the joined per-URL reasons in the message (e.g. '404 Not Found from ...') to see the actual HTTP failure and fix accordingly.
  2. 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.
  3. Check AUTOSKILLS_REGISTRY_BASE_URL / registryBaseUrl points to a valid raw base ending with the skills-registry prefix.
  4. Fix network/proxy access to the registry host and retry; confirm the target branch/tag exists on the remote.

Example fix

// before
AUTOSKILLS_REGISTRY_BASE_URL=https://raw.githubusercontent.com/org/repo/wrong-branch/packages/autoskills/skills-registry
// 404 from every attempt -> 'download failed for skills/foo/SKILL.md: 404 Not Found from ...'

// after
AUTOSKILLS_REGISTRY_BASE_URL=https://raw.githubusercontent.com/org/repo/main/packages/autoskills/skills-registry
Defensive patterns

Strategy: try-catch

Validate before calling

// probe every candidate base URL before installing
async function baseOk(baseUrl) {
  try {
    const res = await fetch(`${baseUrl}/registry.json`);
    return res.ok;
  } catch { return false; }
}

Try / catch

try {
  await downloadRegistryEntry(name, entry, dest);
} catch (e) {
  if (e.message.startsWith("download failed for ")) {
    const reasons = e.message.split("download failed for ")[1];
    logger.error("All registry mirrors failed", { reasons });
    throw new Error(`Registry unreachable — check paths/network. Details: ${reasons}`);
  } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of midudev/autoskills@0ec725320d (2026-09-15). Data as JSON: /api/errors/999c6b8c6ac515e4. Report an issue: GitHub.

Appendix: source

Thrown at packages/autoskills/installer.ts:321

        );
      }
      errors.push(`${res.status} ${res.statusText} from ${baseUrl}`);
      opts.onTrace?.(`miss ${normalizedRel}: ${res.status} ${res.statusText} from ${baseUrl}`);
      continue;
    }

    const buf = Buffer.from(await res.arrayBuffer());
    const actual = sha256Buffer(buf);
    if (actual !== expected) {
      errors.push(`hash mismatch from ${baseUrl}`);
      opts.onTrace?.(`hash mismatch for ${normalizedRel} from ${baseUrl}`);
      continue;
    }
    opts.onTrace?.(`downloaded ${normalizedRel} from ${url}`);
    return { buf, url };
  }

  throw new Error(`download failed for ${normalizedRel}: ${errors.join("; ")}`);
}

async function downloadRegistryEntry(
  skillName: string,
  entry: RegistryEntry,
  destDir: string,
  opts: InstallOptions,
): Promise<void> {
  const files = [];
  for (const rel of entry.files) {
    files.push({
      rel: normalizeRegistryRelPath(rel),
      ...(await downloadRegistryFile(skillName, entry, rel, opts)),
    });
  }

  const bundleHash = createHash("sha256")
    .update(

View on GitHub (pinned to 0ec725320d)