{"record":{"id":"7b5d652068279a7e","repo":"juicedata/juicefs","slug":"v1-v-and-v2-v-can-t-be-nil","errorCode":null,"errorMessage":"v1 %v and v2 %v can't be nil","messagePattern":"v1 (.+?) and v2 (.+?) can't be nil","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/version/version.go","lineNumber":68,"sourceCode":"\t}\n\treturn fmt.Sprintf(\"%d.%d.%d%s+%s\", s.major, s.minor, s.patch, pr, s.build)\n}\n\nfunc Version() string {\n\treturn ver.String()\n}\n\nfunc SetVersion(v string) {\n\tver = *Parse(v)\n}\n\nfunc GetVersion() Semver {\n\treturn ver\n}\n\nfunc CompareVersions(v1, v2 *Semver) (int, error) {\n\tif v1 == nil || v2 == nil {\n\t\treturn 0, fmt.Errorf(\"v1 %v and v2 %v can't be nil\", v1, v2)\n\t}\n\tvar less bool\n\tif v1.major != v2.major {\n\t\tless = v1.major < v2.major\n\t} else if v1.minor != v2.minor {\n\t\tless = v1.minor < v2.minor\n\t} else if v1.patch != v2.patch {\n\t\tless = v1.patch < v2.patch\n\t} else if v1.preRelease != v2.preRelease {\n\t\tless = v1.preRelease < v2.preRelease\n\t\tif v1.preRelease == \"\" || v2.preRelease == \"\" {\n\t\t\tless = !less\n\t\t}\n\t} else {\n\t\treturn 0, nil\n\t}\n\tif less {\n\t\treturn -1, nil","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/pkg/version/version.go#L50-L86","documentation":"CompareVersions compares two *Semver values; if either pointer is nil it returns 0 with 'v1 %v and v2 %v can't be nil'. It is a defensive guard preventing nil dereference when comparing parsed versions.","triggerScenarios":"Calling CompareVersions (directly or via compareVersion, canShutdownGracefully, CheckCliVersion) with a nil version — usually ParseSemver failed earlier and its error/nil result was ignored.","commonSituations":"Upgrade-status checks against a client whose version string failed to parse; comparing against an uninitialized cached version; config where the version field is empty.","solutions":["Check the error from ParseSemver before calling CompareVersions","Ensure the version string being parsed is well-formed (e.g. '1.2.0')","Guard with a nil check before comparison"],"exampleFix":"// before\nn, _ := version.ParseSemver(v)\nres, err := version.CompareVersions(n, m)\n// after\nn, err := version.ParseSemver(v)\nif err != nil { return err }\nres, err := version.CompareVersions(n, m)","handlingStrategy":"type-guard","validationCode":"if v1 == nil || v2 == nil { return errors.New(\"nil version\") }","typeGuard":"func nonNilSemver(v *version.Semver) bool { return v != nil }","tryCatchPattern":"if _, err := CompareVersions(a, b); err != nil { log.Fatalf(\"version compare failed: %v\", err) }","preventionTips":["Always check ParseSemver's error before comparing","Cache parsed versions, not raw strings","Initialize version globals at startup"],"tags":["version","nil","argument"],"backgroundTag":"null-argument","analyzedSha":"c9a67b23e8e08ec23ec331aa6f1675e2319e921c","analyzedAt":"2026-09-06T17:55:48.476Z","contentChangedAt":"2026-09-06T17:55:48.476Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}