heygen-com/hyperframes · error · InvalidProjectError
Invalid project directory: #
Error message
Invalid project directory: #
What it means
resolveProjectOrThrow special-cases dirArg === '#' (after trim). '#' is a URL fragment, not a filesystem path — it appears when a user pastes a URL or a shell-quoting artifact where the project directory argument should go. The library throws InvalidProjectError with a targeted hint and suggestion rather than letting it fall through to the generic 'Not a directory' check, because the '#' case is a known copy-paste footgun.
Source
Thrown at packages/cli/src/utils/project.ts:37
readonly hint?: string;
readonly suggestion?: string;
constructor(title: string, hint?: string, suggestion?: string) {
super(title);
this.name = "InvalidProjectError";
this.title = title;
this.hint = hint;
this.suggestion = suggestion;
}
}
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.",View on GitHub (pinned to c2996c8626)
Solutions
- Run from inside your project directory with `.` or no argument: `hyperframes preview .`.
- Pass the actual project path: `hyperframes preview /path/to/project`.
- If the '#' came from a URL, strip everything from '#' onwards before passing it as a path.
- Audit wrapper scripts for unquoted variable expansions that could yield '#'.
Example fix
# before hyperframes preview # # after hyperframes preview . # from inside the project directory
Defensive patterns
Strategy: validation
Validate before calling
function isLikelyValidProjectArg(v: string | undefined): boolean {
const t = v?.trim();
return t !== undefined && t !== '' && t !== '#';
}
if (!isLikelyValidProjectArg(process.argv[2])) {
throw new Error('Pass a project directory (or `.`); got: ' + process.argv[2]);
} Type guard
function isNonFragmentPath(v: unknown): v is string {
return typeof v === 'string' && v.trim() !== '' && v.trim() !== '#';
} Try / catch
try {
return resolveProjectOrThrow(dirArg);
} catch (err) {
if (err instanceof InvalidProjectError && /Invalid project directory: #/.test(err.message)) {
console.error(err.hint, err.suggestion);
} else throw err;
} Prevention
- Quote shell variables to prevent '#' leakage from URLs/history expansion.
- Default the project arg to '.' in wrapper scripts rather than forwarding raw user input.
- Strip URL fragments (#...) from pasted paths before passing them to the CLI.
When it happens
Trigger: Running a CLI command with '#' as the project argument: `hyperframes preview #`, or a shell-expanded variable that resolved to '#', or pasting a URL whose fragment leaked into argv. Also when a script passes through an unescaped anchor reference.
Common situations: User copies a URL like https://example.com/composition# and the trailing # lands as argv; a bash history substitution gone wrong (!# expansion); an empty arg that defaulted to '#' in a wrapper script; CI config that echoes a URL fragment into the project slot.
Related errors
- Not a directory: ${dir}
- invalid-vars
- ${source}: ${errorMessage(error)}
- --batch must be a JSON array of objects, or an object with a
- ${source} contains zero rows.
AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12).
Data as JSON: /api/errors/14b2682608a57616.
Report an issue: GitHub.