charmbracelet/vhs · error · parser.Error

Invalid regexp pattern: ${literal}

Error message

Invalid regexp pattern: ${literal}

What it means

Fires in parseSet when the value given for the WaitPattern setting fails regexp.Compile, i.e. it is not a syntactically valid Go regular expression. The invalid pattern is still stored in cmd.Args and the error is recorded.

Source

Thrown at parser/parser.go:461

//	Set <setting> <value>
func (p *Parser) parseSet() Command {
	cmd := Command{Type: token.SET}

	if token.IsSetting(p.peek.Type) {
		cmd.Options = p.peek.Literal
	} else {
		p.errors = append(p.errors, NewError(p.peek, "Unknown setting: "+p.peek.Literal))
	}
	p.nextToken()

	switch p.cur.Type {
	case token.WAIT_TIMEOUT:
		cmd.Args = p.parseTime()
	case token.WAIT_PATTERN:
		cmd.Args = p.peek.Literal
		_, err := regexp.Compile(p.peek.Literal)
		if err != nil {
			p.errors = append(p.errors, NewError(p.peek, "Invalid regexp pattern: "+p.peek.Literal))
		}
		p.nextToken()
	case token.LOOP_OFFSET:
		cmd.Args = p.peek.Literal
		p.nextToken()
		// Allow LoopOffset without '%'
		// Set LoopOffset 20
		cmd.Args += "%"
		if p.peek.Type == token.PERCENT {
			p.nextToken()
		}
	case token.TYPING_SPEED:
		cmd.Args = p.peek.Literal
		p.nextToken()
		// Allow TypingSpeed to have bare units (e.g. 10ms)
		// Set TypingSpeed 10ms
		if p.peek.Type == token.MILLISECONDS ||
			p.peek.Type == token.SECONDS {

View on GitHub (pinned to c073383b5d)

Solutions

  1. Fix the regex syntax, e.g. close unmatched '(' or '[' groups
  2. Escape special characters that should match literally, e.g. \. for a dot
  3. Test the pattern with a Go regex tester (RE2 syntax) before putting it in the tape
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at parser/parser.go:461 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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