{"record":{"id":"09dc74ebf7ac2cb6","repo":"temporalio/temporal","slug":"invalid-task-range-min-v-is-larger-than-max-v","errorCode":null,"errorMessage":"invalid task range, min %v is larger than max %v","messagePattern":"invalid task range, min (.+?) is larger than max (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"service/history/queues/range.go","lineNumber":21,"sourceCode":"import (\n\t\"fmt\"\n\n\t\"go.temporal.io/server/service/history/tasks\"\n)\n\ntype (\n\tRange struct {\n\t\tInclusiveMin tasks.Key\n\t\tExclusiveMax tasks.Key\n\t}\n)\n\nfunc NewRange(\n\tinclusiveMin tasks.Key,\n\texclusiveMax tasks.Key,\n) Range {\n\tif inclusiveMin.CompareTo(exclusiveMax) > 0 {\n\t\tpanic(fmt.Sprintf(\"invalid task range, min %v is larger than max %v\", inclusiveMin, exclusiveMax))\n\t}\n\n\treturn Range{\n\t\tInclusiveMin: inclusiveMin,\n\t\tExclusiveMax: exclusiveMax,\n\t}\n}\n\nfunc (r *Range) IsEmpty() bool {\n\treturn r.InclusiveMin.CompareTo(r.ExclusiveMax) == 0\n}\n\nfunc (r *Range) ContainsKey(\n\tkey tasks.Key,\n) bool {\n\treturn key.CompareTo(r.InclusiveMin) >= 0 &&\n\t\tkey.CompareTo(r.ExclusiveMax) < 0\n}","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/service/history/queues/range.go#L3-L39","documentation":"NewRange validates that the inclusive min key does not exceed the exclusive max key, panicking otherwise. A task range must satisfy InclusiveMin <= ExclusiveMax; anything else is a programming error in range construction.","triggerScenarios":"Calling NewRange with min > max — e.g. computing boundaries in the wrong order, a Split producing inverted halves, or a completed range whose bounds crossed after updates.","commonSituations":"Negative or zero task IDs skewing key comparison; time-based keys built with start/stop swapped; tests or utilities constructing ranges from user input without ordering.","solutions":["Validate/swap arguments: if tasks.Key.Compare(min, max) > 0, swap before calling NewRange","Fix the upstream computation that produced inverted bounds (e.g. Split or time-window logic)","Use tasks.MinKey/tasks.MaxKey when combining bounds to guarantee ordering","Add a test asserting the caller's range-building helper for edge-case keys"],"exampleFix":"// before\nr := tasks.NewRange(loadedMax, loadedMin) // inverted\n// after\nif loadedMin.CompareTo(loadedMax) > 0 {\n    loadedMin, loadedMax = loadedMax, loadedMin\n}\nr := tasks.NewRange(loadedMin, loadedMax)","handlingStrategy":"validation","validationCode":"if inclusiveMin.CompareTo(exclusiveMax) > 0 {\n    inclusiveMin, exclusiveMax = exclusiveMax, inclusiveMin\n}\nr := tasks.NewRange(inclusiveMin, exclusiveMax)","typeGuard":null,"tryCatchPattern":"func safeNewRange(minKey, maxKey tasks.Key) (r queues.Range) {\n    defer func() {\n        if rec := recover(); rec != nil {\n            r = queues.Range{}\n        }\n    }()\n    return tasks.NewRange(minKey, maxKey)\n}","preventionTips":["Normalize min/max with tasks.MinKey/tasks.MaxKey before constructing","Double-check time-derived keys for start/end swaps","Assert ordering in range-building helpers with unit tests","Never pass user- or config-derived keys unchecked into NewRange"],"tags":["go","panic","validation","task-range","history-service"],"backgroundTag":"invalid-range-bounds","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}