heygen-com/hyperframes · error · InvalidProjectError
Not a directory: ${dir}
Error message
Not a directory: ${dir} What it means
resolveProjectOrThrow: the resolved path (dirArg ?? '.', made absolute via resolve()) either does not exist (existsSync false) or exists but is not a directory (statSync().isDirectory() false). This is the generic not-a-directory guard that fires for any bad path that is not the special '#' case. Thrown as InvalidProjectError with title 'Not a directory: <abs path>'.
Source
Thrown at packages/cli/src/utils/project.ts:49
export function resolveProjectOrThrow(
dirArg: string | undefined,
options: ResolveProjectOptions = {},
): ProjectDir {
const trimmed = dirArg?.trim();
if (trimmed === "#") {
throw new InvalidProjectError(
"Invalid project directory: #",
"# is a URL fragment, not a project path.",
"Run hyperframes preview . from your project directory.",
);
}
const dir = resolve(dirArg ?? ".");
const name = basename(dir);
const indexPath = resolve(dir, "index.html");
if (!existsSync(dir) || !statSync(dir).isDirectory()) {
throw new InvalidProjectError("Not a directory: " + dir);
}
if (options.requireIndex !== false && !existsSync(indexPath)) {
throw new InvalidProjectError(
"No composition found in " + dir,
"No index.html file found.",
"Run npx hyperframes init to create a new composition.",
);
}
return { dir, name, indexPath };
}
export function resolveProject(
dirArg: string | undefined,
options: ResolveProjectOptions = {},
): ProjectDir {
try {
return resolveProjectOrThrow(dirArg, options);View on GitHub (pinned to c2996c8626)
Solutions
- Verify the path exists and is a directory: `ls -ld <path>`.
- Pass the project directory (containing index.html), not the HTML file itself.
- Use an absolute path or run from inside the project with '.'.
- Check for typos, trailing spaces, or unexpanded ~ (use $HOME or the expanded path).
Example fix
# before: passed the html file, not the directory hyperframes render ./index.html # after hyperframes render .
Defensive patterns
Strategy: validation
Validate before calling
import { existsSync, statSync } from 'node:fs';
import { resolve } from 'node:path';
function ensureProjectDir(dirArg: string | undefined): string {
const dir = resolve(dirArg ?? '.');
if (!existsSync(dir) || !statSync(dir).isDirectory()) {
throw new Error(`Not a directory: ${dir}`);
}
return dir;
} Type guard
import { Stats } from 'node:fs';
function isDirectory(stats: Stats): boolean {
return stats.isDirectory();
} Try / catch
try {
return resolveProjectOrThrow(dirArg);
} catch (err) {
if (err instanceof InvalidProjectError && /^Not a directory:/.test(err.message)) {
console.error(err.message, '— pass the project directory, not a file.');
} else throw err;
} Prevention
- Pass the project directory (the folder containing index.html), not the HTML file.
- Use absolute paths in CI to avoid cwd-relative surprises.
- Verify the path with ls -ld before invoking the CLI.
When it happens
Trigger: Passing a path to a file instead of a directory; a typo in the project path; a relative path resolved against an unexpected cwd; a path on a filesystem that is not mounted; a symlink loop or a broken symlink; passing '.' from a directory that itself was deleted.
Common situations: User runs `hyperframes render index.html` (file, not dir) instead of `hyperframes render .`; wrong cwd when using a relative path; a CI checkout step that did not clone the project; a path with a trailing slash or space that resolved wrong; a deleted/moved project folder.
Related errors
- Invalid project directory: #
- No composition found in ${dir}
- [s3Transport] upload source missing: ${localPath}
- [s3Transport] tar source must be an existing directory: ${so
- [s3Transport] tarball missing: ${tarballPath}
AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12).
Data as JSON: /api/errors/aff89b5a3e9689c1.
Report an issue: GitHub.