{"record":{"id":"4cfd1040fb479eb6","repo":"heygen-com/hyperframes","slug":"media-analysis-requires-a-local-project-asset-fre","errorCode":null,"errorMessage":"Media analysis requires a local project asset; freeze remote media with media-use first","messagePattern":"Media analysis requires a local project asset; freeze remote media with media-use first","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/commands/media-treatment.ts","lineNumber":497,"sourceCode":"function mediaSourceForElement(element: Element): string {\n  const src =\n    element.getAttribute(\"src\") ??\n    (element.tagName.toLowerCase() === \"video\"\n      ? element.querySelector(\"source\")?.getAttribute(\"src\")\n      : null);\n  if (!src) throw new Error(\"Selected media has no analyzable src\");\n  return src;\n}\n\nexport function resolveMediaTreatmentSource(\n  projectDir: string,\n  compositionFile: string,\n  source: string,\n): string {\n  const sourceUrl = source.trim();\n  if (!sourceUrl) throw new Error(\"Selected media has no analyzable local src\");\n  if (isRemoteOrInlineUrl(sourceUrl)) {\n    throw new Error(\n      \"Media analysis requires a local project asset; freeze remote media with media-use first\",\n    );\n  }\n  const cleanSource = cleanAssetUrl(sourceUrl);\n  if (!cleanSource) throw new Error(\"Selected media has no analyzable local src\");\n  const projectRelative = cleanSource.startsWith(\"/\")\n    ? cleanSource\n    : rewriteAssetPath(compositionFile, cleanSource, (path) => existsSync(join(projectDir, path)));\n  const asset = resolveExistingLocalAsset(projectDir, projectRelative);\n  if (!asset) throw new Error(`Media file not found: ${source}`);\n  return asset.resolved;\n}\n\nfunction parseGrading(raw: string | undefined, apply: boolean, clear: boolean): unknown {\n  if (clear) {\n    if (raw !== undefined || apply) {\n      throw new Error(\"Use either --apply with --grading or --clear, not both\");\n    }","sourceCodeStart":479,"sourceCodeEnd":515,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/cli/src/commands/media-treatment.ts#L479-L515","documentation":"Thrown by resolveMediaTreatmentSource when the selected media element's src is a remote URL (http/https) or an inline data: URI. The --analyze path must read raw file bytes from disk to measure color/luma/HDR metadata, so it cannot operate on media that lives outside the project. The message directs you to first materialize the asset locally via the media-use command.","triggerScenarios":"Running `hyperframes media-treatment --selector '#hero' --analyze` where the matched <img>/<video> has src=\"https://cdn.example.com/hero.jpg\" or src=\"data:image/png;base64,...\". Also reached programmatically by calling resolveMediaTreatmentSource with a source string that isRemoteOrInlineUrl() returns true for.","commonSituations":"Compositions that reference stock photos, CDN-hosted video, or base64-embedded images. Agents that skip the media-use freeze step and jump straight to --analyze. Migrating a composition from remote to local assets but forgetting to update the analyze workflow.","solutions":["Run `hyperframes media-use <remote-url>` to download/freeze the asset into the project, which rewrites the src to a local path","Re-run `hyperframes media-treatment --selector '#hero' --analyze` after the src is local","If you intentionally want to keep the remote src, skip --analyze and use --capabilities or --apply with a known preset instead","Programmatically, check isRemoteOrInlineUrl(source) before calling resolveMediaTreatmentSource and pre-freeze or skip analysis"],"exampleFix":"// before\n<img src=\"https://cdn.example.com/hero.jpg\" id=\"hero\">\n// freeze the remote asset locally first\n//   hyperframes media-use https://cdn.example.com/hero.jpg\n// src is now a local project path; analyze succeeds\nhyperframes media-treatment --selector '#hero' --analyze","handlingStrategy":"validation","validationCode":"import { isRemoteOrInlineUrl } from '@hyperframes/parsers/asset-resolution';\n\nfunction assertLocalAssetForAnalysis(source: string): void {\n  if (isRemoteOrInlineUrl(source.trim())) {\n    throw new Error('Source is remote/inline — run `hyperframes media-use` to freeze it locally first.');\n  }\n}\n// call before resolveMediaTreatmentSource\nassertLocalAssetForAnalysis(source);","typeGuard":null,"tryCatchPattern":"try {\n  const path = resolveMediaTreatmentSource(projectDir, compositionFile, source);\n} catch (e) {\n  if (e instanceof Error && /freeze remote media/.test(e.message)) {\n    // run media-use, then retry\n  } else throw e;\n}","preventionTips":["Always run media-use on remote assets before invoking --analyze","In agent loops, check isRemoteOrInlineUrl(source) and branch to the freeze step automatically"],"tags":["media-treatment","remote-asset","cli","validation"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}