charmbracelet/vhs · error · parser.Error
Not a valid modifier
Error message
Not a valid modifier
What it means
When parsing a Ctrl command's arguments, vhs only accepts modifiers and single keys: keyword keys (Enter, Space, Tab, arrows like Up/Down), or single-character strings. Any other token — notably a string longer than one character that is not a known key — produces this error, immediately followed by 'Invalid control argument: <literal>'.
Source
Thrown at parser/parser.go:339
case peek.Type == token.ENTER,
peek.Type == token.SPACE,
peek.Type == token.BACKSPACE,
peek.Type == token.MINUS,
peek.Type == token.AT,
peek.Type == token.LEFT_BRACKET,
peek.Type == token.RIGHT_BRACKET,
peek.Type == token.CARET,
peek.Type == token.BACKSLASH,
peek.Type == token.LEFT,
peek.Type == token.RIGHT,
peek.Type == token.UP,
peek.Type == token.DOWN,
peek.Type == token.STRING && len(peek.Literal) == 1:
args = append(args, peek.Literal)
default:
// Key arguments with len > 1 are not valid
p.errors = append(p.errors,
NewError(p.cur, "Not a valid modifier"),
NewError(p.cur, "Invalid control argument: "+p.cur.Literal))
}
p.nextToken()
}
if len(args) == 0 {
p.errors = append(p.errors, NewError(p.cur, "Expected control character with args, got "+p.cur.Literal))
}
ctrlArgs := strings.Join(args, " ")
return Command{Type: token.CTRL, Args: ctrlArgs}
}
// parseAlt parses an alt command.
// An alt command takes a character to type while the modifier is held down.
//
// Alt+<character>View on GitHub (pinned to c073383b5d)
Solutions
- Use valid key names from vhs's keys list (Enter, Space, Tab, Backspace, Delete, Up, Down, Left, Right, PageUp, PageDown, etc.) with correct capitalization.
- Use single characters for character keys: 'Ctrl+a', not 'Ctrl+a!' typos.
- Check token.Keywords / keys.go for the exact supported key set.
Example fix
// before (.tape) Ctrl+abc // after (.tape) Ctrl+c
Defensive patterns
Strategy: validation
Validate before calling
func validCtrlArg(a string) bool { if len(a) == 1 { return true }; _, ok := token.Keywords[a]; return ok } Type guard
func isKnownKey(s string) bool { k, ok := token.Keywords[s]; return ok && k != token.ILLEGAL } Prevention
- Use vhs's exact key names with correct capitalization (Enter, Space, Tab, Down...)
- Single characters for character keys; nothing else in Ctrl chains
- Check keys.go / token package for the supported key set
When it happens
Trigger: A Ctrl argument is a multi-character string that is not a registered key keyword, e.g. 'Ctrl+abc', 'Ctrl+enter' (lowercase, not a keyword), or 'Ctrl+F12' if that key is not in token.Keywords.
Common situations: Lowercasing key names ('ctrl+enter' when keywords are case-sensitive); trying key names vhs does not define; pasting combos from other tools' syntax.
Related errors
- Invalid control argument: ${literal}
- Wait+ expects Line or Screen
- Modifiers must come before other characters
- Expected control character with args, got ${literal}
- Invalid command: ${literal}
AI-assisted analysis of charmbracelet/vhs@c073383b5d (2026-09-02).
Data as JSON: /api/errors/687a39abfbcc5761.
Report an issue: GitHub.