charmbracelet/vhs · error · parser.Error
Modifiers must come before other characters
Error message
Modifiers must come before other characters
What it means
Ctrl in vhs accepts chains of modifier keys (Ctrl, Alt, Shift) followed by a regular key, e.g. 'Ctrl+Shift+a'. Modifiers must appear at the start of the chain; once a non-modifier key has been consumed, a later modifier is invalid. parseCtrl enforces this with inModifierChain and raises this error when a modifier keyword appears after the chain has ended.
Source
Thrown at parser/parser.go:306
// 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>
// E.g:
// Ctrl+Shift+O
// Ctrl+Alt+Shift+P
func (p *Parser) parseCtrl() Command {
var args []string
inModifierChain := true
for p.peek.Type == token.PLUS {
p.nextToken()
peek := p.peek
// Get key from keywords and check if it's a valid modifier
if k := token.Keywords[peek.Literal]; token.IsModifier(k) {
if !inModifierChain {
p.errors = append(p.errors, NewError(p.cur, "Modifiers must come before other characters"))
// Clear args so the error is returned
args = nil
continue
}
args = append(args, peek.Literal)
p.nextToken()
continue
}
inModifierChain = false
// Add key argument.
switch {
case peek.Type == token.ENTER,
peek.Type == token.SPACE,
peek.Type == token.BACKSPACE,
peek.Type == token.MINUS,View on GitHub (pinned to c073383b5d)
Solutions
- Reorder so all modifiers (Ctrl/Alt/Shift) come first, then the character key: 'Ctrl+Shift+a'.
- Split into separate Ctrl commands if the combination is not a modifier chain.
Example fix
// before (.tape) Ctrl+a+Shift // after (.tape) Ctrl+Shift+a
Defensive patterns
Strategy: validation
Validate before calling
func isModifierFirst(keys []string) bool { i := 0; for i < len(keys) && isMod(keys[i]) { i++ }; for ; i < len(keys); i++ { if isMod(keys[i]) { return false } }; return true }
func isMod(k string) bool { switch k { case "Ctrl", "Alt", "Shift": return true }; return false } Prevention
- Order key combos modifier-first: Ctrl, Alt, Shift, then the character key
- Think of the combo name ('Ctrl+Shift+a'), not the physical press order
- Split unrelated combos into separate commands
When it happens
Trigger: A modifier keyword (ctrl/alt/shift) appears after a regular key in a Ctrl argument list, e.g. 'Ctrl+a+Shift' or 'Ctrl+a+alt+b'.
Common situations: Reordering keys from muscle memory ('Ctrl+c+alt' instead of 'Ctrl+Alt+c'); writing key combos in the order pressed on a keyboard rather than modifier-first order.
Related errors
- Not a valid modifier
- Invalid control argument: ${literal}
- Expected control character with args, 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/d83f67a4db31f616.
Report an issue: GitHub.