heygen-com/hyperframes · error · Error
Color grading requires an <img> or <video>; selector matched
Error message
Color grading requires an <img> or <video>; selector matched <${tag}> What it means
Thrown by selectMediaElement() in packages/cli/src/commands/media-treatment.ts:440. After resolving a single element, it lowercases tagName and requires 'img' or 'video' — color grading only applies to media. Any other tag (div, picture, source, a, span, etc.) throws, naming the matched tag.
Source
Thrown at packages/cli/src/commands/media-treatment.ts:441
matches = queryIncludingTemplates(document, selector);
} catch {
throw new Error(`Invalid selector: ${selector}`);
}
if (matches.length === 0) throw new Error(`Selector did not match: ${selector}`);
if (selectorIndex === undefined && matches.length > 1) {
throw new Error(
`Selector matched ${matches.length} elements; use a unique selector or --selector-index`,
);
}
const resolvedIndex = selectorIndex ?? 0;
const element = matches[resolvedIndex];
if (!element) {
throw new Error(`--selector-index ${resolvedIndex} is outside ${matches.length} matches`);
}
const tag = element.tagName.toLowerCase();
if (tag !== "img" && tag !== "video") {
throw new Error(`Color grading requires an <img> or <video>; selector matched <${tag}>`);
}
return { element, selectorIndex: resolvedIndex, tag };
}
export function applyMediaTreatmentToHtml(
source: string,
options: ApplyMediaTreatmentOptions,
): ApplyMediaTreatmentResult {
const { element, selectorIndex, tag } = selectMediaElement(
source,
options.selector,
options.selectorIndex,
);
const before = parseStoredGrading(element.getAttribute(HF_COLOR_GRADING_ATTR));
const value = options.clear ? null : serializeGradingPatch(before, options.grading);
const changed = element.getAttribute(HF_COLOR_GRADING_ATTR) !== value;View on GitHub (pinned to c2996c8626)
Solutions
- Make the selector resolve to the actual <img> or <video> element (e.g. '#hero img' instead of '#hero').
- For <picture>, target the inner <img>; for <video> with <source> children, target the <video> itself.
- Inspect the matched tag in the error message and adjust the selector accordingly.
Example fix
<!-- DOM: <div id="hero"><img src="hero.png"></div> -->
# before -- matched <div>
hyperframes media-treatment --selector '#hero' --grading '{...}' --apply
# after -- target the img
hyperframes media-treatment --selector '#hero img' --grading '{...}' --apply Defensive patterns
Strategy: type-guard
Validate before calling
import { parseHTML } from 'linkedom';
function selectorTargetsMedia(selector: string, source: string): boolean {
const { document } = parseHTML(source);
const el = document.querySelector(selector);
if (!el) return false;
const tag = el.tagName.toLowerCase();
return tag === 'img' || tag === 'video';
} Type guard
function isMediaTag(tag: string): tag is 'img' | 'video' {
return tag === 'img' || tag === 'video';
} Try / catch
try {
selectMediaElement(source, selector);
} catch (error) {
if (/Color grading requires an <img> or <video>/.test(String(error))) {
// target the inner img/video instead of the wrapper
selectMediaElement(source, `${selector} img, ${selector} video`);
} else throw error;
} Prevention
- Target the actual <img>/<video>, not a wrapper, <picture>, or <source>.
- For <picture>, select the child <img>; for <video>, select the <video> not <source>.
- Inspect the matched tag name reported in the error to adjust.
When it happens
Trigger: A selector that resolves to a non-media element: a wrapper div around an image, a <picture> element, a <source> inside a <video>, an <a> wrapping an image, etc.
Common situations: Targeting '.hero' which is the wrapper div, not the img inside; targeting <picture> instead of its child <img>; targeting <source> instead of the parent <video>.
Related errors
- Invalid selector: ${selector}
- Selector did not match: ${selector}
- Selector matched ${matches.length} elements; use a unique se
- --selector-index ${resolvedIndex} is outside ${matches.lengt
- Selected media has no analyzable src
AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12).
Data as JSON: /api/errors/62ed6917161f1509.
Report an issue: GitHub.