{"record":{"id":"72a11fe3ed9aea21","repo":"router-for-me/CLIProxyAPI","slug":"weight-must-be-an-integer","errorCode":null,"errorMessage":"weight must be an integer","messagePattern":"weight must be an integer","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"warning","filePath":"internal/api/handlers/management/config_lists.go","lineNumber":23,"sourceCode":"\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/gin-gonic/gin\"\n\t\"github.com/router-for-me/CLIProxyAPI/v7/internal/config\"\n)\n\nfunc parseCredentialWeightPatch(raw json.RawMessage) (*int, error) {\n\tif len(raw) == 0 {\n\t\treturn nil, fmt.Errorf(\"weight is missing\")\n\t}\n\tif bytes.Equal(bytes.TrimSpace(raw), []byte(\"null\")) {\n\t\treturn nil, nil\n\t}\n\tvar weight int\n\tdecoder := json.NewDecoder(bytes.NewReader(raw))\n\tif errDecode := decoder.Decode(&weight); errDecode != nil {\n\t\treturn nil, fmt.Errorf(\"weight must be an integer\")\n\t}\n\tif errValidate := config.ValidateCredentialWeight(&weight); errValidate != nil {\n\t\treturn nil, errValidate\n\t}\n\treturn &weight, nil\n}\n\nfunc rejectInvalidCredentialWeight(c *gin.Context, field string, weight *int) bool {\n\tif errValidate := config.ValidateCredentialWeight(weight); errValidate != nil {\n\t\tc.JSON(400, gin.H{\"error\": fmt.Sprintf(\"%s: %v\", field, errValidate)})\n\t\treturn true\n\t}\n\treturn false\n}\n\n// Generic helpers for list[string]\nfunc (h *Handler) putStringList(c *gin.Context, set func([]string), after func()) {\n\tdata, err := c.GetRawData()","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/api/handlers/management/config_lists.go#L5-L41","documentation":"parseCredentialWeightPatch could not JSON-decode the weight value into an int — the raw bytes are valid JSON but not an integer literal: a string (\"3\"), a float (2.5), a bool, an array/object, or trailing content after the number. Weights must be whole numbers and are further constrained by config.ValidateCredentialWeight.","triggerScenarios":"PATCHing a credential's weight with 2.5, \"3\", true, or {\"value\":3}; clients sending weights as strings because their config layer typed them as text.","commonSituations":"Frontend forms binding weight to a text input; loosely typed (any) payloads in TypeScript clients; JSON generators quoting numbers; locale formatting inserting decimal separators.","solutions":["Send a plain JSON integer for weight (no quotes, no decimals)","Validate client-side before the request that weight is an integer within the configured bounds","If a fractional or quoted value is legitimate in your UX, convert to int before sending","Check config.ValidateCredentialWeight's bounds so the follow-up validation does not reject the value"],"exampleFix":"// before\n{\"weight\": \"3\"}\n// after\n{\"weight\": 3}","handlingStrategy":"type-guard","validationCode":"var w float64\nif err := json.Unmarshal(raw, &w); err != nil || w != math.Trunc(w) {\n    return errors.New(\"weight must be an integer\")\n}","typeGuard":"func isJSONInt(raw json.RawMessage) bool {\n    var w int\n    dec := json.NewDecoder(bytes.NewReader(raw))\n    return dec.Decode(&w) == nil && dec.More() == false\n}","tryCatchPattern":"if err := decoder.Decode(&weight); err != nil {\n    c.JSON(400, gin.H{\"error\": \"weight must be a JSON integer, e.g. 3\"})\n}","preventionTips":["Type weight as an integer number in client schemas","Validate payload shape with JSON Schema before sending","Never quote numeric fields"],"tags":["validation","json","type-mismatch","user-input"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}