charmbracelet/vhs · error · parser.Error

Expected path after Screenshot

Error message

Expected path after Screenshot

What it means

parseScreenshot requires a STRING path token after the Screenshot directive. If the next token is not a string, it records "Expected path after Screenshot" and returns. Screenshot writes a capture at that point in the recording, so a destination path is required.

Source

Thrown at parser/parser.go:760

			srcCmd.Type == token.OUTPUT {
			continue
		}
		filtered = append(filtered, srcCmd)
	}

	p.nextToken()
	return filtered
}

// parseScreenshot parses screenshot command.
// Screenshot command takes a file path for storing screenshot.
//
//	Screenshot <path>
func (p *Parser) parseScreenshot() Command {
	cmd := Command{Type: token.SCREENSHOT}

	if p.peek.Type != token.STRING {
		p.errors = append(p.errors, NewError(p.cur, "Expected path after Screenshot"))
		p.nextToken()
		return cmd
	}

	path := p.peek.Literal

	// Check if path has .png extension
	ext := filepath.Ext(path)
	if ext != ".png" {
		p.errors = append(p.errors, NewError(p.peek, "Expected file with .png extension"))
		p.nextToken()
		return cmd
	}

	cmd.Args = path
	p.nextToken()

	return cmd

View on GitHub (pinned to c073383b5d)

Solutions

  1. Add a quoted destination: `Screenshot "out.png"`
  2. Remove the Screenshot line if not needed
  3. Ensure the path is double-quoted so the lexer emits a STRING token

Example fix

// before
Screenshot ./out.png
// after
Screenshot "./out.png"
Defensive patterns

Strategy: validation

Validate before calling

line := `Screenshot "out.png"`
if strings.HasPrefix(strings.TrimSpace(line), "Screenshot") {
    rest := strings.TrimSpace(strings.TrimPrefix(strings.TrimSpace(line), "Screenshot"))
    if !strings.HasPrefix(rest, `"`) {
        return fmt.Errorf("Screenshot requires a quoted path: %s", line)
    }
}

Type guard

func screenshotHasPath(t token.Token) bool { return t.Type == token.STRING && t.Literal != "" }

Try / catch

if err := parse(tape); err != nil && strings.Contains(err.Error(), "Expected path after Screenshot") {
    return fmt.Errorf("bad Screenshot directive in %s: %w", tape, err)
}

Prevention

When it happens

Trigger: A .tape file with bare `Screenshot`, `Screenshot ./out.png` (unquoted), or `Screenshot 42` — parseScreenshot sees peek.Type != token.STRING.

Common situations: Forgetting the argument when adding mid-recording screenshots; using shell-style unquoted paths; editor auto-complete dropping the quotes.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of charmbracelet/vhs@c073383b5d (2026-09-02). Data as JSON: /api/errors/99fad3b96917f195. Report an issue: GitHub.