{"record":{"id":"88da91646a4f945c","repo":"upstash/context7","slug":"no-files","errorCode":null,"errorMessage":"no files","messagePattern":"no files","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"packages/cli/src/commands/setup.ts","lineNumber":368,"sourceCode":"    const result = await installRule(agentName, \"mcp\", scope);\n    ruleStatus = result.status;\n    rulePath = result.path;\n  } catch (err) {\n    ruleStatus = `failed: ${err instanceof Error ? err.message : String(err)}`;\n    rulePath = \"\";\n  }\n\n  const skillDir =\n    scope === \"global\"\n      ? agent.skill.dir(\"global\")\n      : join(process.cwd(), agent.skill.dir(\"project\"));\n  const skillPath = join(skillDir, agent.skill.name, \"SKILL.md\");\n\n  let skillStatus: string;\n  try {\n    const downloadData = await downloadSkill(\"/upstash/context7\", agent.skill.name);\n    if (downloadData.error || downloadData.files.length === 0) {\n      throw new Error(downloadData.error || \"no files\");\n    }\n    await installSkillFiles(agent.skill.name, downloadData.files, skillDir);\n    skillStatus = \"installed\";\n  } catch (err) {\n    skillStatus = `failed: ${err instanceof Error ? err.message : String(err)}`;\n  }\n\n  return {\n    agent: agent.displayName,\n    mcpStatus,\n    mcpPath,\n    ruleStatus,\n    rulePath,\n    skillStatus,\n    skillPath,\n  };\n}\n","sourceCodeStart":350,"sourceCodeEnd":386,"githubUrl":"https://github.com/upstash/context7/blob/ca15df0443ee770506fc4eb270d1efc71d483933/packages/cli/src/commands/setup.ts#L350-L386","documentation":"Thrown inside the setup command after downloadSkill() returns for an agent skill. It fires when downloadData.error is set OR the returned files array is empty. The surrounding try/catch immediately converts it into a human-readable skillStatus string (\"failed: no files\"), so it never escapes to the caller — it is a status sentinel, not a propagated exception.","triggerScenarios":"The upstream skill bundle (e.g. /upstash/context7) was fetched but contained zero files; the download endpoint returned an error payload; the registry returned a manifest with no file entries; a transient upstream issue produced an empty archive.","commonSituations":"Running setup for an agent whose skill has been removed or renamed upstream; partial/network-truncated download that parsed as an empty result; version mismatch between the CLI and the registry contract; first run right after a registry migration.","solutions":["Retry the setup command — empty downloads are often transient.","Confirm the skill slug passed to downloadSkill matches a current registry entry.","Upgrade the CLI to the latest version so the download/parse contract matches the registry.","If it persists, inspect downloadData (log it temporarily) to distinguish a real error from a genuinely empty payload."],"exampleFix":"// before\nif (downloadData.error || downloadData.files.length === 0) {\n  throw new Error(downloadData.error || \"no files\");\n}\n\n// after — distinguish the two cases in the status string\nif (downloadData.error) {\n  throw new Error(downloadData.error);\n}\nif (downloadData.files.length === 0) {\n  throw new Error(\"skill bundle contained no files (upstream registry issue)\");\n}","handlingStrategy":"validation","validationCode":"// downloadSkill result is already available — validate before throwing.\nconst downloadData = await downloadSkill(\"/upstash/context7\", agent.skill.name);\nif (downloadData.error) {\n  skillStatus = `failed: ${downloadData.error}`;\n} else if (downloadData.files.length === 0) {\n  skillStatus = \"failed: skill bundle was empty (retry; if persistent, upgrade CLI)\";\n} else {\n  await installSkillFiles(agent.skill.name, downloadData.files, skillDir);\n  skillStatus = \"installed\";\n}","typeGuard":"function isDownloadResult(v: unknown): v is { error?: string; files: { path: string; content: string }[] } {\n  return typeof v === \"object\" && v !== null && Array.isArray((v as any).files);\n}","tryCatchPattern":"// Already handled: the surrounding try/catch converts the throw into skillStatus.\n// Keep it — but log the downloadData shape so 'no files' is diagnosable.\ntry {\n  const d = await downloadSkill(slug, name);\n  if (d.error || d.files.length === 0) throw new Error(d.error || \"no files\");\n  await installSkillFiles(name, d.files, skillDir);\n  skillStatus = \"installed\";\n} catch (err) {\n  console.error(\"skill download failed:\", slug, name, err);\n  skillStatus = `failed: ${err instanceof Error ? err.message : String(err)}`;\n}","preventionTips":["Pin a known-good CLI version that matches the current registry contract.","Retry setup once before reporting failure — empty bundles are often transient.","Log the skill slug and file count on failure so empty-vs-error cases are distinguishable."],"tags":["cli","setup","skill-install","non-propagated"],"backgroundTag":null,"analyzedSha":"ca15df0443ee770506fc4eb270d1efc71d483933","analyzedAt":"2026-08-12T13:31:48.440Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}