heygen-com/hyperframes · critical

Project archive must include index.html at the root. Check t

Error message

Project archive must include index.html at the root. Check that .hyperframesignore does not exclude it.

What it means

buildPublishFileMap walks the project dir (respecting .hyperframesignore, IGNORED_DIRS like node_modules/.git/dist, and DEFAULT_PROJECT_IGNORE like /renders/ /snapshots/) and collects relative file paths. If 'index.html' is not among the collected relative paths, publish cannot proceed — a published project must have an entry composition. The message points at .hyperframesignore because that is the usual culprit: an overly broad ignore pattern excluded index.html.

Source

Thrown at packages/cli/src/utils/publishProject.ts:491

    }
  }

  return ctx.externalMap.size;
}

/**
 * Walk the project dir, read every non-ignored file, and localize external
 * (out-of-project) asset references. Returns the in-memory archive file map —
 * the seam `publish.ts` hooks a proxy-baking transform into (U6) between this
 * and `zipPublishFileMap` below. `cloud render` never sees this seam: it
 * keeps calling `createPublishArchive` directly.
 */
export function buildPublishFileMap(projectDir: string): Map<string, Buffer> {
  const absProjectDir = resolve(projectDir);
  const filePaths: string[] = [];
  collectProjectFiles(absProjectDir, absProjectDir, filePaths, createProjectIgnore(absProjectDir));
  if (!filePaths.includes("index.html")) {
    throw new Error(
      "Project archive must include index.html at the root. Check that .hyperframesignore does not exclude it.",
    );
  }

  const fileContents = new Map<string, Buffer>();
  for (const filePath of filePaths) {
    fileContents.set(filePath, readFileSync(join(absProjectDir, filePath)));
  }

  localizeExternalAssets(absProjectDir, fileContents);
  return fileContents;
}

/** Zip an in-memory archive file map (from `buildPublishFileMap`, optionally
 * transformed in between, e.g. by proxy baking) into the final archive buffer. */
export function zipPublishFileMap(fileContents: Map<string, Buffer>): PublishArchiveResult {
  const archive = new AdmZip();
  for (const [filePath, content] of fileContents) {

View on GitHub (pinned to c2996c8626)

Solutions

  1. Confirm index.html exists at the ROOT of the directory passed to publish: ls <project-dir>/index.html.
  2. Inspect .hyperframesignore for patterns matching index.html (e.g. `*.html`, `/index.*`) and remove/narrow them.
  3. Run publish from the directory that actually contains index.html.
  4. If index.html is generated, ensure the generation step runs before publish.

Example fix

# .hyperframesignore before (excludes index.html)
*.html
# after
/renders/*.html
/snapshots/*.html
Defensive patterns

Strategy: validation

Validate before calling

import { existsSync, readFileSync } from 'node:fs';
import { resolve } from 'node:path';
import ignore from 'ignore';

function ensureIndexHtmlIncluded(projectDir: string): void {
  const abs = resolve(projectDir, 'index.html');
  if (!existsSync(abs)) throw new Error('index.html missing from project root');
  const ig = ignore().add(readFileSync(resolve(projectDir, '.hyperframesignore'), 'utf-8').catch?.() ?? '');
  if (ig.ignores('index.html')) throw new Error('.hyperframesignore excludes index.html');
}

Try / catch

try {
  return buildPublishFileMap(projectDir);
} catch (err) {
  if (err instanceof Error && /must include index.html at the root/.test(err.message)) {
    // surface the .hyperframesignore contents so the user can find the offending pattern
    console.error(err.message, '\nCheck .hyperframesignore patterns.');
  } else throw err;
}

Prevention

When it happens

Trigger: index.html is missing from the project root entirely; .hyperframesignore contains a pattern that matches index.html (e.g. `/*.html`, `/index.*`, `index.html`); index.html exists only in a subdirectory (the walker records relative paths, so a nested index.html becomes 'subdir/index.html', not 'index.html'); the project root passed to publish is the wrong directory.

Common situations: User added `*.html` or `/index.html` to .hyperframesignore to exclude build artifacts, accidentally excluding the entry; a monorepo where the publish root was set to the workspace, not the package; an index.html that lives in src/ but publish is run from the parent; a generated project where index.html was gitignored and not checked out.

Related errors


AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12). Data as JSON: /api/errors/be898f6064962bd0. Report an issue: GitHub.