heygen-com/hyperframes · error · AddError

install-failed

install-failed

Error message

Install failed: ${err instanceof Error ? err.message : String(err)}

What it means

AddError with code 'install-failed', thrown by installAll as a catch-all wrapper around the per-item installItem loop. Any error from writing files, creating directories, or item-level validation is re-wrapped so the command surfaces a consistent exit code; the original error message is preserved in the AddError message. Because the installer validates every target before writing, a mid-loop failure still leaves earlier items written.

Source

Thrown at packages/cli/src/commands/add.ts:194

// Install a topologically-ordered plan (dependencies first, requested item
// last). The installer validates every target before any write; a failure on
// any item surfaces as an install-failed AddError. Returns all written paths.
async function installAll(
  installPlan: RegistryItem[],
  destDir: string,
  baseUrl: string | undefined,
  force: boolean,
): Promise<{ written: string[]; preserved: string[] }> {
  const written: string[] = [];
  const preserved: string[] = [];
  try {
    for (const planItem of installPlan) {
      const result = await installItem(planItem, { destDir, baseUrl, force });
      written.push(...result.written);
      preserved.push(...result.preserved);
    }
  } catch (err) {
    throw new AddError(
      `Install failed: ${err instanceof Error ? err.message : String(err)}`,
      "install-failed",
    );
  }
  return { written, preserved };
}

export async function runAdd(opts: RunAddArgs): Promise<RunAddResult> {
  const projectDir = resolve(opts.projectDir);

  // 1. Load (or write default) project config.
  let config = loadProjectConfig(projectDir);
  const hasConfig = existsSync(projectConfigPath(projectDir));
  if (!hasConfig && existsSync(resolve(projectDir, "index.html"))) {
    writeProjectConfig(projectDir, DEFAULT_PROJECT_CONFIG);
    config = DEFAULT_PROJECT_CONFIG;
  }

View on GitHub (pinned to c2996c8626)

Solutions

  1. Read the inner message in 'Install failed: <inner>' — it names the exact file and filesystem error.
  2. Re-run with --force if the cause is an existing target you intend to overwrite.
  3. Fix permissions on the project directory (chown/chmod) or run from a location you own.
  4. Free disk space or clear the registry cache if the inner error is ENOSPC.

Example fix

# before: existing file blocks the install
$ hyperframes add my-block   # install-failed: EEXIST ...

# after: explicitly overwrite
$ hyperframes add my-block --force
Defensive patterns

Strategy: try-catch

Validate before calling

import { access, constants } from 'node:fs/promises';
async function assertWritable(dir: string) {
  await access(dir, constants.W_OK);
}
await assertWritable(resolve(projectDir));

Try / catch

try {
  await runAdd(opts);
} catch (err) {
  if (err instanceof AddError && err.code === 'install-failed') {
    if (/EEXIST/.test(err.message)) opts.force = true;   // retry with --force
    else throw err;
  }
}

Prevention

When it happens

Trigger: Filesystem permission denied on destDir, a target path collision that force=false refuses to overwrite, disk full, an EACCES/EPERM on the registry cache, or installItem throwing on a malformed item manifest.

Common situations: Running without write permission to the project (read-only mount, root-owned dir); a pre-existing file at the target without --force; symlink or case-collision on case-insensitive filesystems; full disk in CI.

Related errors


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