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 nil

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Use exactly one expectation prefix per line: either `! cmd` (expect failure) or `? cmd` (allow either) — never both.
  2. Remove the duplicate prefix token.
  3. 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

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.