heygen-com/hyperframes · error
Malformed skills manifest from ${sourceLabel}
Error message
Malformed skills manifest from ${sourceLabel} What it means
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.
Source
Thrown at packages/cli/src/utils/skillsManifest.ts:637
for (let i = 0; i < 16; i++) {
const p = join(dir, MANIFEST_FILE);
if (existsSync(p)) return p;
const parent = join(dir, "..");
if (parent === dir) break;
dir = parent;
}
return null;
}
/**
* Narrow an untrusted JSON payload to a SkillsManifest, or throw a clear error.
* Guards against a CDN serving an error page (or a malformed manifest) as 200 —
* without this, a bad shape surfaces later as a cryptic crash in diffSkills.
*/
function asSkillsManifest(data: unknown, sourceLabel: string): SkillsManifest {
const m = data as Partial<SkillsManifest> | null;
if (!m || typeof m !== "object" || typeof m.skills !== "object" || m.skills === null) {
throw new Error(`Malformed skills manifest from ${sourceLabel}`);
}
return m as SkillsManifest;
}
async function fetchManifest(url: string): Promise<SkillsManifest> {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
try {
const res = await fetch(url, { signal: controller.signal, headers: { Connection: "close" } });
if (!res.ok) throw new Error(`HTTP ${res.status} fetching ${url}`);
return asSkillsManifest(await res.json(), url);
} finally {
clearTimeout(timeout);
}
}
/**
* Resolve main's live HEAD sha via `git ls-remote`. GitHub's branch-raw CDNView on GitHub (pinned to c2996c8626)
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.
Defensive patterns
Strategy: type-guard
Type guard
function isSkillsManifest(data: unknown): data is SkillsManifest {
return (
data !== null &&
typeof data === "object" &&
typeof (data as SkillsManifest).skills === "object" &&
(data as SkillsManifest).skills !== null
);
} Try / catch
try {
const manifest = await fetchRemoteManifest(source);
} catch (err) {
if (err instanceof Error && err.message.startsWith("Malformed skills manifest")) {
// Fall back to a local/bundled manifest or skip the update
console.warn(`Remote manifest malformed, falling back to local: ${err.message}`);
return resolveLocalManifest(fallbackPath);
}
throw err;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- can't check skills freshness (GitHub manifest unreachable) —
- HTTP ${res.status} fetching ${url}
- Unknown skill(s): ${unknown.join(", ")}. Available: ${[...ma
- No skills manifest found at: ${source}
- [build-zip] npm install into staging failed (status ${result
AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12).
Data as JSON: /api/errors/22fd7b5184216835.
Report an issue: GitHub.