{"record":{"id":"4f2ad4bfe41d95b6","repo":"Billionmail/BillionMail","slug":"invalid-operator","errorCode":null,"errorMessage":"Invalid operator: ","messagePattern":"Invalid operator: ","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/public/common.go","lineNumber":1702,"sourceCode":"}\n\n// Get user ID by context\nfunc GetAccountIdByCtx(ctx context.Context) int {\n\tusername := GetUserName(ctx)\n\t// Get user ID\n\taccountInfo, err := M(\"account\").Where(\"username=?\", username).Fields(\"account_id\").One()\n\tif err != nil && accountInfo == nil {\n\t\treturn 0\n\t}\n\taccountId := accountInfo[\"account_id\"].Int()\n\treturn accountId\n}\n\n// Compare version numbers\nfunc VersionCompare(version1, version2, opt string) bool {\n\t// Check operator\n\tif opt != \">\" && opt != \">=\" && opt != \"<\" && opt != \"<=\" && opt != \"==\" && opt != \"=\" {\n\t\tpanic(\"Invalid operator: \" + opt)\n\t}\n\n\tv1 := strings.Split(version1, \".\")\n\tv2 := strings.Split(version2, \".\")\n\tif len(v1) != len(v2) {\n\t\t// Pad\n\t\tif len(v1) > len(v2) {\n\t\t\tfor i := 0; i < len(v1)-len(v2); i++ {\n\t\t\t\tv2 = append(v2, \"0\")\n\t\t\t}\n\t\t} else {\n\t\t\tfor i := 0; i < len(v2)-len(v1); i++ {\n\t\t\t\tv1 = append(v1, \"0\")\n\t\t\t}\n\t\t}\n\t}\n\n\tlength := len(v1)","sourceCodeStart":1684,"sourceCodeEnd":1720,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/public/common.go#L1684-L1720","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Use only one of the supported operators: >, >=, <, <=, ==, =.","Normalize the input before calling: trim whitespace and map unsupported operators (e.g. convert \"!=\" to a negated comparison).","Refactor VersionCompare to return an error instead of panicking, and validate the operator at the call site."],"exampleFix":"// before\nif VersionCompare(cur, want, \"!=\") { ... } // panics\n// after\nisNewer := VersionCompare(cur, want, \">\")\nisOlder := VersionCompare(cur, want, \"<\")\nif isNewer || isOlder { /* versions differ */ }","handlingStrategy":"validation","validationCode":"var validOps = map[string]bool{\">\":true, \">=\":true, \"<\":true, \"<=\":true, \"==\":true, \"=\":true}\nif !validOps[strings.TrimSpace(opt)] {\n    return fmt.Errorf(\"unsupported version operator %q\", opt)\n}\nresult := VersionCompare(v1, v2, strings.TrimSpace(opt))","typeGuard":"func isVersionOperator(op string) bool {\n    return op==\">\"||op==\">=\"||op==\"<\"||op==\"<=\"||op==\"==\"||op==\"=\"\n}","tryCatchPattern":"func safeCompare(a, b, op string) (ok bool, err error) {\n    defer func() {\n        if r := recover(); r != nil {\n            err = fmt.Errorf(\"VersionCompare panicked: %v\", r)\n        }\n    }()\n    ok = VersionCompare(a, b, op)\n    return\n}","preventionTips":["Keep the allowed operator list in one shared constant/map used by both UI and code","Trim operator strings coming from config files or env","Never pass user-supplied strings directly as operators"],"tags":["panic","validation","versioning","go"],"backgroundTag":"invalid-comparison-operator","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}