charmbracelet/vhs · error · parser.Error
${literal} expects string
Error message
${literal} expects string What it means
Fires in parseType when the token after the Type command (and optional speed option) is not a STRING, i.e. no text to type was given. The loop that concatenates string tokens never runs, so the Type command ends up with an empty Args.
Source
Thrown at parser/parser.go:587
// parseShow parses a Show command.
//
// Show
func (p *Parser) parseShow() Command {
cmd := Command{Type: token.SHOW}
return cmd
}
// parseType parses a type command.
// A type command takes a string to type.
//
// Type "string"
func (p *Parser) parseType() Command {
cmd := Command{Type: token.TYPE}
cmd.Options = p.parseSpeed()
if p.peek.Type != token.STRING {
p.errors = append(p.errors, NewError(p.peek, p.cur.Literal+" expects string"))
}
for p.peek.Type == token.STRING {
p.nextToken()
cmd.Args += p.cur.Literal
// If the next token is a string, add a space between them.
// Since tokens must be separated by a whitespace, this is most likely
// what the user intended.
//
// Although it is possible that there may be multiple spaces / tabs between
// the tokens, however if the user was intending to type multiple spaces
// they would need to use a string literal.
if p.peek.Type == token.STRING {
cmd.Args += " "
}
}View on GitHub (pinned to c073383b5d)
Solutions
- Quote the text to type, e.g. Type "hello world"
- Move the typing speed option so it does not swallow the string, e.g. Type@100ms "text"
- Remove the Type command if nothing should be typed
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at parser/parser.go:587 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/703d3b4717a79830.
Report an issue: GitHub.