{"record":{"id":"479383e470694a90","repo":"charmbracelet/vhs","slug":"expected-file-with-png-extension","errorCode":null,"errorMessage":"Expected file with .png extension","messagePattern":"Expected file with \\.png extension","errorType":"validation","errorClass":"parser.Error","httpStatus":null,"severity":"error","filePath":"parser/parser.go","lineNumber":770,"sourceCode":"// parseScreenshot parses screenshot command.\n// Screenshot command takes a file path for storing screenshot.\n//\n//\tScreenshot <path>\nfunc (p *Parser) parseScreenshot() Command {\n\tcmd := Command{Type: token.SCREENSHOT}\n\n\tif p.peek.Type != token.STRING {\n\t\tp.errors = append(p.errors, NewError(p.cur, \"Expected path after Screenshot\"))\n\t\tp.nextToken()\n\t\treturn cmd\n\t}\n\n\tpath := p.peek.Literal\n\n\t// Check if path has .png extension\n\text := filepath.Ext(path)\n\tif ext != \".png\" {\n\t\tp.errors = append(p.errors, NewError(p.peek, \"Expected file with .png extension\"))\n\t\tp.nextToken()\n\t\treturn cmd\n\t}\n\n\tcmd.Args = path\n\tp.nextToken()\n\n\treturn cmd\n}\n\n// Errors returns any errors that occurred during parsing.\nfunc (p *Parser) Errors() []Error {\n\treturn p.errors\n}\n\n// nextToken gets the next token from the lexer\n// and updates the parser tokens accordingly.\nfunc (p *Parser) nextToken() {","sourceCodeStart":752,"sourceCodeEnd":788,"githubUrl":"https://github.com/charmbracelet/vhs/blob/c073383b5de0b1f57bf514113029c306bc986539/parser/parser.go#L752-L788","documentation":"This parser error is raised by the Screenshot command parser when its argument path does not end in the `.png` extension. The library only supports saving screenshots as PNG files, so during parsing of `Screenshot <path>` it validates `filepath.Ext(path) == \".png\"` and appends this error to the parser's error list otherwise. The offending path is not accepted as the command's argument, so the Screenshot command is effectively dropped from the parsed output.","triggerScenarios":"Calling `Parser.Parse` on a script containing a `Screenshot` directive whose argument is a quoted or bare path with any extension other than `.png` (e.g. `Screenshot \"out.jpg\"`, `Screenshot shot.jpeg`, `Screenshot capture` with no extension). The check happens at parse time in parseScreenshot, before any command executes.","commonSituations":"Hand-written or generated tape/command files where the screenshot output was given as .jpg/.jpeg/.gif/.bmp/.webp or omitted the extension entirely; refactoring scripts that changed output format; tools or scripts that template a screenshot path from a variable set to a non-PNG filename.","solutions":["Rename the Screenshot target to use a `.png` extension, e.g. change `Screenshot \"shot.jpg\"` to `Screenshot \"shot.png\"`.","If the file must be another format, save it as .png first and convert afterwards (e.g. with ImageMagick: `magick shot.png shot.jpg`) instead of asking the Screenshot command for that format.","Check the exact literal passed to Screenshot for typos or case issues such as `.PNG` or `.Png`; normalize the extension to lowercase `.png`.","Inspect `parser.Errors()` after parsing your script and fix every reported line rather than only this occurrence, since parseScreenshot returns early and skips adding the argument to the command.","If the path comes from a variable or template, print/interpolate it to verify the extension is actually `.png` in the final script."],"exampleFix":"// before\ntype \"Enter\"\nScreenshot \"output/demo.jpg\"\n\n// after\ntype \"Enter\"\nScreenshot \"output/demo.png\"","handlingStrategy":"validation","validationCode":"for _, path := range screenshotPaths {\n    if filepath.Ext(path) != \".png\" {\n        return fmt.Errorf(\"screenshot path %q must end in .png\", path)\n    }\n}\n// now safe to run the script through the parser","typeGuard":"func isPNGPath(p string) bool {\n    return strings.EqualFold(filepath.Ext(p), \".png\")\n}","tryCatchPattern":null,"preventionTips":["Always name Screenshot targets with a lowercase `.png` extension when writing script/tape files.","Pre-validate all screenshot paths in your script files before handing them to the parser, rejecting any whose filepath.Ext is not \".png\".","After parsing, always check `parser.Errors()` rather than assuming the parse succeeded; this error is reported there, not via panic.","If your tooling generates the scripts, template screenshot output names with a hard-coded \".png\" suffix.","Convert non-PNG outputs after capture (png -> jpg etc.) rather than requesting non-PNG formats from the Screenshot command."],"tags":["parser","validation","file-extension","screenshot"],"backgroundTag":"invalid-file-extension","analyzedSha":"c073383b5de0b1f57bf514113029c306bc986539","analyzedAt":"2026-09-02T01:53:05.682Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}