Billionmail/BillionMail · error

Invalid operator:

Error message

Invalid operator: 

What it means

VersionCompare in core/internal/service/public/common.go compares two dotted version strings and only accepts a fixed set of operators. It panics with "Invalid operator: <opt>" when the operator argument is anything other than >, >=, <, <=, == or =. This is a programmer-error signal rather than a runtime failure.

Source

Thrown at core/internal/service/public/common.go:1702

}

// Get user ID by context
func GetAccountIdByCtx(ctx context.Context) int {
	username := GetUserName(ctx)
	// Get user ID
	accountInfo, err := M("account").Where("username=?", username).Fields("account_id").One()
	if err != nil && accountInfo == nil {
		return 0
	}
	accountId := accountInfo["account_id"].Int()
	return accountId
}

// Compare version numbers
func VersionCompare(version1, version2, opt string) bool {
	// Check operator
	if opt != ">" && opt != ">=" && opt != "<" && opt != "<=" && opt != "==" && opt != "=" {
		panic("Invalid operator: " + opt)
	}

	v1 := strings.Split(version1, ".")
	v2 := strings.Split(version2, ".")
	if len(v1) != len(v2) {
		// Pad
		if len(v1) > len(v2) {
			for i := 0; i < len(v1)-len(v2); i++ {
				v2 = append(v2, "0")
			}
		} else {
			for i := 0; i < len(v2)-len(v1); i++ {
				v1 = append(v1, "0")
			}
		}
	}

	length := len(v1)

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Use only one of the supported operators: >, >=, <, <=, ==, =.
  2. Normalize the input before calling: trim whitespace and map unsupported operators (e.g. convert "!=" to a negated comparison).
  3. Refactor VersionCompare to return an error instead of panicking, and validate the operator at the call site.

Example fix

// before
if VersionCompare(cur, want, "!=") { ... } // panics
// after
isNewer := VersionCompare(cur, want, ">")
isOlder := VersionCompare(cur, want, "<")
if isNewer || isOlder { /* versions differ */ }
Defensive patterns

Strategy: validation

Validate before calling

var validOps = map[string]bool{">":true, ">=":true, "<":true, "<=":true, "==":true, "=":true}
if !validOps[strings.TrimSpace(opt)] {
    return fmt.Errorf("unsupported version operator %q", opt)
}
result := VersionCompare(v1, v2, strings.TrimSpace(opt))

Type guard

func isVersionOperator(op string) bool {
    return op==">"||op==">="||op=="<"||op=="<="||op=="=="||op=="="
}

Try / catch

func safeCompare(a, b, op string) (ok bool, err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("VersionCompare panicked: %v", r)
        }
    }()
    ok = VersionCompare(a, b, op)
    return
}

Prevention

When it happens

Trigger: Calling VersionCompare(v1, v2, opt) with an operator string outside the accepted set: "!="", "<>", "===", "~>", an empty string, or a value with stray whitespace like "> " (trailing space fails the comparison).

Common situations: Developers pass an operator from user config or a DB-stored filter value, expect "!=" to work, or build the operator dynamically and get an unexpected value; whitespace-padded values from YAML/env parsing also trigger it.

Related errors


AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05). Data as JSON: /api/errors/4f2ad4bfe41d95b6. Report an issue: GitHub.