charmbracelet/vhs · error · parser.Error
Expected time after ${literal}
Error message
Expected time after ${literal} What it means
vhs's parseTime reads a duration value for commands that accept one (TypingSpeed via Set, Sleep, and the @speed suffix). It expects a NUMBER token first; if the next token is not a number it emits 'Expected time after <literal>', where <literal> is the command or unit token that expected a numeric argument.
Source
Thrown at parser/parser.go:273
count := p.peek.Literal
p.nextToken()
return count
}
return "1"
}
// parseTime parses a time argument.
//
// <number>[ms]
func (p *Parser) parseTime() string {
var t string
if p.peek.Type == token.NUMBER {
t = p.peek.Literal
p.nextToken()
} else {
p.errors = append(p.errors, NewError(p.cur, "Expected time after "+p.cur.Literal))
return ""
}
// Allow TypingSpeed to have bare units (e.g. 50ms, 100ms)
if p.peek.Type == token.MILLISECONDS || p.peek.Type == token.SECONDS || p.peek.Type == token.MINUTES {
t += p.peek.Literal
p.nextToken()
} else {
t += "s"
}
return t
}
// parseCtrl parses a control command.
// A control command takes one or multiples characters and/or modifiers to type while ctrl is held down.
//
// Ctrl[+Alt][+Shift]+<char>View on GitHub (pinned to c073383b5d)
Solutions
- Provide a number, with or without a unit: 'Sleep 5', 'Sleep 500ms', 'Set TypingSpeed 50ms'.
- Ensure the number comes before the unit: 'Sleep 5s', not 'Sleep s5'.
- Check the @ speed suffix syntax: 'Wait@5s', not 'Wait@s'.
Example fix
// before (.tape) Sleep ms // after (.tape) Sleep 500ms
Defensive patterns
Strategy: validation
Validate before calling
func hasNumericTime(args []string) bool { if len(args) == 0 { return false }; _, err := strconv.ParseFloat(args[0], 64); return err == nil } Prevention
- Always put the number before the unit: 'Sleep 5s' not 'Sleep s5'
- Never write a unit without a preceding number
- Review tape diffs for accidentally deleted duration values
When it happens
Trigger: 'Sleep ms' or 'Sleep s' (unit without a number), 'Set TypingSpeed' with no value, or 'Wait@ s' where the '@' is followed by a unit instead of a number — anything where the token after the time-taking keyword is not a NUMBER.
Common situations: Omitting the numeric value ('Sleep' with no argument is handled elsewhere, but 'Sleep 5' vs 'Sleep s' confusion); unit-first ordering; assuming bare units like 'ms' alone are valid durations.
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
- Wait expects positive duration
- Expected control character with args, got ${literal}
- Expected alt character, got ${literal}
- Invalid command: ${literal}
- Wait+ expects Line or Screen
AI-assisted analysis of charmbracelet/vhs@c073383b5d (2026-09-02).
Data as JSON: /api/errors/865d67981f217df1.
Report an issue: GitHub.