{"record":{"id":"57b0c291b31d184f","repo":"vercel-labs/skills","slug":"downloaded-url-is-not-a-valid-skill-md-file-or-sup","errorCode":null,"errorMessage":"Downloaded URL is not a valid SKILL.md file or supported archive","messagePattern":"Downloaded URL is not a valid SKILL\\.md file or supported archive","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/download-source.ts","lineNumber":286,"sourceCode":"    const downloadedStats = await stat(downloadedFile);\n    if (downloadedStats.size === 0) {\n      throw new Error('Downloaded URL is empty');\n    }\n\n    if (await isValidSkillMarkdown(downloadedFile)) {\n      const skillDir = join(tempDir, 'skill');\n      await mkdir(skillDir, { recursive: true });\n      await writeFile(join(skillDir, 'SKILL.md'), await readFile(downloadedFile));\n      return { rootDir: skillDir, tempDir, kind: 'skill-md' };\n    }\n\n    await mkdir(extractDir, { recursive: true });\n    if (await tryExtractArchive(downloadedFile, extractDir, limits)) {\n      const rootDir = (await getSingleTopLevelDirectory(extractDir)) ?? extractDir;\n      return { rootDir, tempDir, kind: 'archive' };\n    }\n\n    throw new Error('Downloaded URL is not a valid SKILL.md file or supported archive');\n  } catch (error) {\n    await rm(tempDir, { recursive: true, force: true }).catch(() => {});\n    throw error;\n  }\n}\n","sourceCodeStart":268,"sourceCodeEnd":292,"githubUrl":"https://github.com/vercel-labs/skills/blob/435076e78988e1e6ec40d00b0b1d76bdbbc5419a/src/download-source.ts#L268-L292","documentation":"Final fallback error in downloadSource(): the downloaded non-empty file is neither a valid SKILL.md (isValidSkillMarkdown) nor an archive that tryExtractArchive can extract. It means the URL's content type is simply unsupported by the CLI.","triggerScenarios":"downloadSource() downloads a file, isValidSkillMarkdown() rejects it (missing frontmatter/name fields), and tryExtractArchive() returns false because the bytes are not gzip/zip/tar — then this generic error is thrown.","commonSituations":"Adding a URL that serves HTML (GitHub blob page instead of raw), a README.md without valid SKILL.md frontmatter, a .tar.bz2/.7z archive, or a JSON/YAML manifest the CLI does not understand.","solutions":["Open the URL with curl and confirm it serves raw content, not HTML (use raw.githubusercontent.com for GitHub files)","If adding a single file, ensure it is a valid SKILL.md with the required frontmatter (name, description)","If adding an archive, use .zip or .tar.gz, which are the supported formats","Alternatively clone the repo and run 'skills add <local-path>'"],"exampleFix":"# before\nskills add https://github.com/org/repo/blob/main/SKILL.md\n# after\nskills add https://raw.githubusercontent.com/org/repo/main/SKILL.md","handlingStrategy":"try-catch","validationCode":"const head = await fetch(url);\nconst ct = head.headers.get('content-type') ?? '';\nconst ok = /text\\/plain|markdown|octet-stream|zip|gzip|tar/.test(ct);\nif (!ok) throw new Error(`URL serves unsupported type: ${ct}`);","typeGuard":"function isUnsupportedDownload(e: unknown): e is Error {\n  return e instanceof Error && /not a valid SKILL\\.md file or supported archive/.test(e.message);\n}","tryCatchPattern":"try { await downloadSource(url); }\ncatch (e) {\n  if (isUnsupportedDownload(e)) {\n    // fall back to cloning the repo and adding from a local path\n    const dir = await cloneRepo(gitUrlFor(url));\n    return addFromLocalPath(dir);\n  }\n  throw e;\n}","preventionTips":["Always use raw file URLs, not blob/HTML pages","Validate SKILL.md frontmatter (name, description) before publishing","Support only .zip/.tar.gz artifacts in your registry"],"tags":["download","content-type","skill-md","archive"],"backgroundTag":"unsupported-content-format","analyzedSha":"435076e78988e1e6ec40d00b0b1d76bdbbc5419a","analyzedAt":"2026-08-28T17:47:53.369Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}