{"record":{"id":"bd13eea7f7e4c738","repo":"heygen-com/hyperframes","slug":"file-must-be-an-html-file-inside-the-project","errorCode":null,"errorMessage":"--file must be an HTML file inside the project","messagePattern":"--file must be an HTML file inside the project","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/commands/media-treatment.ts","lineNumber":577,"sourceCode":"    args.apply,\n    args.analyze,\n  ].some(Boolean);\n  if (hasMutationOption) throw new Error(\"--capabilities cannot be combined with mutation options\");\n  if (args.all === true && capability)\n    throw new Error(\"Use either --all or --capability, not both\");\n\n  let capabilities: unknown = getMediaTreatmentCapabilityOverview();\n  if (args.all === true) capabilities = getHfColorGradingCapabilities();\n  else if (capability) capabilities = getMediaTreatmentCapabilityDetail(capability);\n  console.log(JSON.stringify(withMeta({ ok: true, capabilities }), null, 2));\n}\n\nfunction resolveMutationFile(args: MediaTreatmentCommandArgs) {\n  const project = resolveProject(readOptionalString(args.project));\n  const fileArg = readOptionalString(args.file) ?? \"index.html\";\n  const filePath = resolve(project.dir, fileArg);\n  if (!isPathInside(filePath, project.dir) || !filePath.toLowerCase().endsWith(\".html\")) {\n    throw new Error(\"--file must be an HTML file inside the project\");\n  }\n  if (!existsSync(filePath)) throw new Error(`Composition file not found: ${fileArg}`);\n  return { project, filePath };\n}\n\nfunction analyzeTarget(args: MediaTreatmentCommandArgs) {\n  const { project, filePath } = resolveMutationFile(args);\n  const selector = readOptionalString(args.selector);\n  if (!selector) throw new Error(\"--selector is required\");\n  if (\n    readOptionalString(args.grading) ||\n    args.clear === true ||\n    args.apply === true ||\n    args[\"dry-run\"] === true\n  ) {\n    throw new Error(\"--analyze cannot be combined with mutation options\");\n  }\n  const selectorIndex = parseSelectorIndex(readOptionalString(args[\"selector-index\"]));","sourceCodeStart":559,"sourceCodeEnd":595,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/cli/src/commands/media-treatment.ts#L559-L595","documentation":"Thrown by resolveMutationFile when the resolved --file path either falls outside the project directory (path traversal) or does not end with .html. This is a security boundary (isPathInside) combined with an extension guard ensuring only HTML composition files inside the project are mutated.","triggerScenarios":"Passing `--file ../outside.html` (escapes project dir), `--file /etc/passwd` (absolute outside project), or `--file scene.txt` (wrong extension). Also triggered by symlinks resolving outside the project root.","commonSituations":"Monorepo users pointing at a shared composition in a parent directory. Typos like --file index.htm. Agents guessing paths outside the resolved project root.","solutions":["Ensure the file is inside the project directory and ends with .html","Pass --project <dir> to set the correct project root if the file is legitimately in a sibling project","Move or copy the composition into the project directory","Check the extension is exactly .html (not .htm or .xhtml)"],"exampleFix":"// before\nhyperframes media-treatment --file ../shared/scene.html --selector '#hero' --apply\n// after — file inside the project\nhyperframes media-treatment --file compositions/scene.html --selector '#hero' --apply","handlingStrategy":"validation","validationCode":"import { resolve } from 'node:path';\nimport { isPathInside } from '@hyperframes/core';\n\nfunction assertFileInsideProject(projectDir: string, fileArg: string): void {\n  const filePath = resolve(projectDir, fileArg);\n  if (!isPathInside(filePath, projectDir) || !filePath.toLowerCase().endsWith('.html')) {\n    throw new Error('--file must be an HTML file inside the project');\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pass --project when the cwd is not the project root","Use project-relative paths only; never absolute paths outside the project"],"tags":["media-treatment","cli","path-traversal","security","validation"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}