{"record":{"id":"22fd7b5184216835","repo":"heygen-com/hyperframes","slug":"malformed-skills-manifest-from-sourcelabel","errorCode":null,"errorMessage":"Malformed skills manifest from ${sourceLabel}","messagePattern":"Malformed skills manifest from (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cli/src/utils/skillsManifest.ts","lineNumber":637,"sourceCode":"  for (let i = 0; i < 16; i++) {\n    const p = join(dir, MANIFEST_FILE);\n    if (existsSync(p)) return p;\n    const parent = join(dir, \"..\");\n    if (parent === dir) break;\n    dir = parent;\n  }\n  return null;\n}\n\n/**\n * Narrow an untrusted JSON payload to a SkillsManifest, or throw a clear error.\n * Guards against a CDN serving an error page (or a malformed manifest) as 200 —\n * without this, a bad shape surfaces later as a cryptic crash in diffSkills.\n */\nfunction asSkillsManifest(data: unknown, sourceLabel: string): SkillsManifest {\n  const m = data as Partial<SkillsManifest> | null;\n  if (!m || typeof m !== \"object\" || typeof m.skills !== \"object\" || m.skills === null) {\n    throw new Error(`Malformed skills manifest from ${sourceLabel}`);\n  }\n  return m as SkillsManifest;\n}\n\nasync function fetchManifest(url: string): Promise<SkillsManifest> {\n  const controller = new AbortController();\n  const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);\n  try {\n    const res = await fetch(url, { signal: controller.signal, headers: { Connection: \"close\" } });\n    if (!res.ok) throw new Error(`HTTP ${res.status} fetching ${url}`);\n    return asSkillsManifest(await res.json(), url);\n  } finally {\n    clearTimeout(timeout);\n  }\n}\n\n/**\n * Resolve main's live HEAD sha via `git ls-remote`. GitHub's branch-raw CDN","sourceCodeStart":619,"sourceCodeEnd":655,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/cli/src/utils/skillsManifest.ts#L619-L655","documentation":"Thrown by asSkillsManifest when a fetched JSON payload does not narrow to a valid SkillsManifest — specifically when the top-level value is not an object, or when its skills field is missing, not an object, or null. This guards against a CDN or GitHub raw endpoint serving an error page or HTML redirect as a 200 response, which would otherwise cause a cryptic crash later in diffSkills.","triggerScenarios":"A remote manifest URL (GitHub raw, CDN) returns 200 but with HTML content (error page, redirect page) instead of JSON; a manifest that was manually edited and its skills field was deleted or corrupted; the JSON parsed successfully but the structure doesn't have a skills object.","commonSituations":"GitHub raw.githubusercontent.com serving a stale or redirected page after a repo rename; a custom manifest URL pointing to the wrong file; network interception (corporate proxy) injecting an HTML page; a manifest format change in a newer repo version that this CLI doesn't understand.","solutions":["Check the sourceLabel in the error — it contains the exact URL that served the bad payload.","Open the URL in a browser to verify it returns valid JSON with a top-level skills object.","If using a custom repo/source, verify the skills-manifest.json exists at the repo root or that a skills/ directory is present.","Fall back to the default source by omitting the --source flag."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function isSkillsManifest(data: unknown): data is SkillsManifest {\n  return (\n    data !== null &&\n    typeof data === \"object\" &&\n    typeof (data as SkillsManifest).skills === \"object\" &&\n    (data as SkillsManifest).skills !== null\n  );\n}","tryCatchPattern":"try {\n  const manifest = await fetchRemoteManifest(source);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith(\"Malformed skills manifest\")) {\n    // Fall back to a local/bundled manifest or skip the update\n    console.warn(`Remote manifest malformed, falling back to local: ${err.message}`);\n    return resolveLocalManifest(fallbackPath);\n  }\n  throw err;\n}","preventionTips":["Use the default skills source unless a custom one is verified to return valid JSON.","Open the manifest URL in a browser before pointing the CLI at it to verify it returns JSON, not HTML.","Cache a known-good local manifest as a fallback for when remote sources serve bad data."],"tags":["skills","manifest","network","validation"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}