golang/go · error
duplicated '!' or '?' token
Error message
duplicated '!' or '?' token
What it means
Thrown by the script line parser (parse/flushArg) when a command line carries more than one expectation prefix token. The parser recognizes leading '!' (require failure) and '?' (allow either) and stores the first into cmd.want; a second such prefix is rejected because the intended expectation is ambiguous. This is a static syntax error surfaced at parse time before any command runs.
Source
Thrown at src/cmd/internal/script/engine.go:370
quoted = false // currently processing quoted text
)
flushArg := func() error {
if len(rawArg) == 0 {
return nil // Nothing to flush.
}
defer func() { rawArg = nil }()
if cmd.name == "" && len(rawArg) == 1 && !rawArg[0].quoted {
arg := rawArg[0].s
// Command prefix ! means negate the expectations about this command:
// go command should fail, match should not be found, etc.
// Prefix ? means allow either success or failure.
switch want := expectedStatus(arg); want {
case failure, successOrFailure:
if cmd.want != "" {
return errors.New("duplicated '!' or '?' token")
}
cmd.want = want
return nil
}
// Command prefix [cond] means only run this command if cond is satisfied.
if strings.HasPrefix(arg, "[") && strings.HasSuffix(arg, "]") {
want := true
arg = strings.TrimSpace(arg[1 : len(arg)-1])
if strings.HasPrefix(arg, "!") {
want = false
arg = strings.TrimSpace(arg[1:])
}
if arg == "" {
return errors.New("empty condition")
}
cmd.conds = append(cmd.conds, condition{want: want, tag: arg})
return nilView on GitHub (pinned to b6b368adc5)
Solutions
- Use exactly one expectation prefix per line: either `! cmd` (expect failure) or `? cmd` (allow either) — never both.
- Remove the duplicate prefix token.
- If you need 'allow either' plus a condition, use `? [cond] cmd` rather than stacking prefixes.
Example fix
// before ! ! grep foo file # -> duplicated '!' or '?' token // after ! grep foo file
Defensive patterns
Strategy: validation
Validate before calling
// Validate a script line has at most one expectation prefix.
func singleExpectationPrefix(line string) error {
t := strings.TrimSpace(line)
count := 0
for _, p := range []string{"!", "?"} {
if strings.HasPrefix(t, p) {
count++
t = strings.TrimSpace(t[len(p):])
}
}
if count > 1 { return errors.New("duplicated expectation prefix") }
return nil
} Type guard
func isDuplicatePrefix(err error) bool {
return err != nil && err.Error() == "duplicated '!' or '?' token"
} Try / catch
// Static check: lint script files for double ! / ? prefixes before running.
Prevention
- Use exactly one of '!' or '?' per line.
- Lint script-test files for stacked prefixes.
- Remember '!' and '?' do not compose.
When it happens
Trigger: A script line beginning with two expectation prefixes, e.g. `! ! cat file` or `! ? cat file` or `? ! cat file`. The second token hits the `cmd.want != ""` branch and returns the error.
Common situations: Script-test author mistakenly stacks modifiers believing '?' and '!' compose, or a copy-paste leaves a stray prefix. Also a typo where '!!' (shell history-style) is used instead of a single '!'.
Related errors
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/2b5a97243e4aeb9a.
Report an issue: GitHub.