{"record":{"id":"42a851e0244a045b","repo":"Budibase/budibase","slug":"failed-to-retrieve-skeleton-metadata","errorCode":null,"errorMessage":"Failed to retrieve skeleton metadata","messagePattern":"Failed to retrieve skeleton metadata","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cli/src/plugins/skeleton.ts","lineNumber":17,"sourceCode":"import fetch from \"node-fetch\"\nimport fs from \"fs\"\nimport os from \"os\"\nimport { join } from \"path\"\nimport { processStringSync } from \"@budibase/string-templates\"\n\nconst download = require(\"download\")\nconst tar = require(\"tar\")\n\nconst HBS_FILES = [\"package.json.hbs\", \"schema.json.hbs\", \"README.md.hbs\"]\n\nasync function getSkeletonUrl(type: string) {\n  const resp = await fetch(\n    \"https://api.github.com/repos/budibase/budibase-skeleton/releases/latest\"\n  )\n  if (resp.status >= 300) {\n    throw new Error(\"Failed to retrieve skeleton metadata\")\n  }\n  const json = (await resp.json()) as { assets: any[] }\n  for (let asset of json[\"assets\"]) {\n    if (asset.name && asset.name.includes(type)) {\n      return asset[\"browser_download_url\"]\n    }\n  }\n  throw new Error(\"No skeleton found in latest release.\")\n}\n\nexport async function getSkeleton(type: string, name: string) {\n  const url = await getSkeletonUrl(type)\n  const tarballFile = join(os.tmpdir(), \"skeleton.tar.gz\")\n\n  // download the full skeleton tarball\n  fs.writeFileSync(tarballFile, await download(url))\n  fs.mkdirSync(name)\n  // extract it and get what we need","sourceCodeStart":1,"sourceCodeEnd":35,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/cli/src/plugins/skeleton.ts#L1-L35","documentation":"getSkeletonUrl queries the GitHub API for the latest release of the budibase/budibase-skeleton repo. Any HTTP status >= 300 (rate limiting, network/proxy errors, repo unavailable) aborts with this error instead of returning a download URL.","triggerScenarios":"Running the plugin init command when the GET https://api.github.com/repos/budibase/budibase-skeleton/releases/latest request returns a non-2xx status (e.g. 403 rate limit, 404, 5xx, connection failure surfaced as a status).","commonSituations":"Unauthenticated GitHub API rate limiting (60 req/hr per IP) on CI or shared IPs; corporate proxy blocking api.github.com; GitHub outage; offline environment.","solutions":["Wait for the GitHub API rate limit to reset (check the X-RateLimit-Reset header) or run from an IP with quota","Set a GITHUB_TOKEN / use authenticated requests if your environment supports it, and re-run","Verify network/proxy access: `curl -I https://api.github.com/repos/budibase/budibase-skeleton/releases/latest`","Retry later during a GitHub incident (check githubstatus.com)"],"exampleFix":"// diagnose before retrying\ncurl -I https://api.github.com/repos/budibase/budibase-skeleton/releases/latest\n// HTTP/1.1 403 ... \"API rate limit exceeded\" => wait or change network","handlingStrategy":"retry","validationCode":"const resp = await fetch(\"https://api.github.com/repos/budibase/budibase-skeleton/releases/latest\")\nif (!resp.ok) {\n  const remaining = resp.headers.get(\"x-ratelimit-remaining\")\n  if (remaining === \"0\") throw new Error(\"GitHub API rate limited; retry later or authenticate\")\n}","typeGuard":null,"tryCatchPattern":"try {\n  const url = await getSkeletonUrl(type)\n} catch (err) {\n  if ((err as Error).message === \"Failed to retrieve skeleton metadata\") {\n    await new Promise(r => setTimeout(r, 5000))\n    // retry once, or instruct user about rate limits/proxy\n  } else throw err\n}","preventionTips":["Avoid running skeleton downloads from rate-limited shared CI IPs","Check api.github.com reachability behind corporate proxies","Monitor GitHub status during incidents before retrying"],"tags":["network","github-api","cli","http"],"backgroundTag":"github-api-rate-limit","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}