{"record":{"id":"59149ed79ba993a5","repo":"MHSanaei/3x-ui","slug":"invalid-type-for-user-field-q-t","errorCode":null,"errorMessage":"invalid type for user field %q: %T","messagePattern":"invalid type for user field %q: %T","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xray/api.go","lineNumber":68,"sourceCode":"// XrayAPI is a gRPC client for managing Xray core configuration, inbounds, outbounds, and statistics.\ntype XrayAPI struct {\n\tHandlerServiceClient *command.HandlerServiceClient\n\tStatsServiceClient   *statsService.StatsServiceClient\n\tRoutingServiceClient *routerService.RoutingServiceClient\n\tgrpcClient           *grpc.ClientConn\n\tisConnected          bool\n\tStatsLastValues      map[string]int64\n}\n\nfunc getRequiredUserString(user map[string]any, key string) (string, error) {\n\tvalue, ok := user[key]\n\tif !ok || value == nil {\n\t\treturn \"\", fmt.Errorf(\"missing required user field %q\", key)\n\t}\n\n\tstrValue, ok := value.(string)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"invalid type for user field %q: %T\", key, value)\n\t}\n\n\treturn strValue, nil\n}\n\nfunc getOptionalUserString(user map[string]any, key string) (string, error) {\n\tvalue, ok := user[key]\n\tif !ok || value == nil {\n\t\treturn \"\", nil\n\t}\n\n\tstrValue, ok := value.(string)\n\tif !ok {\n\t\treturn \"\", fmt.Errorf(\"invalid type for user field %q: %T\", key, value)\n\t}\n\n\treturn strValue, nil\n}","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/MHSanaei/3x-ui/blob/ad32144c42455696ea9f14e12168beac3e25f5d2/internal/xray/api.go#L50-L86","documentation":"The required-field variant of the type check in getRequiredUserString: the key exists and is non-nil, but its value is not a Go string (e.g. a float64 from JSON numbers, a bool, or a nested map). The %T verb in the message tells you the concrete type that arrived, which pinpoints the serialization mistake upstream.","triggerScenarios":"Building a user map from JSON where a string field was encoded as a number or boolean — e.g. \"email\": 123, or \"publicKey\": {\"b64\": \"...\"} — and passing it into the Xray account builder that calls getRequiredUserString.","commonSituations":"Generated/imported client JSON from external tools with wrong types; a frontend or API consumer sending form values that get coerced to numbers; refactors that changed a field's Go type while stale clients still hold the old shape in the DB.","solutions":["Match the %T in the message to the offending field and fix the producer: ensure the JSON value is a string (quote numbers/booleans where a string is expected).","Correct the stored client settings via the panel editor (re-enter the field) so the regenerated map has the right type.","Add upstream schema validation (Zod/JSON schema on the inbound settings) so type-wrong clients are rejected at the API boundary with a precise path instead of deep inside Xray user building."],"exampleFix":"// before\nuser := map[string]any{\"email\": 12345}\n\n// after\nuser := map[string]any{\"email\": \"12345\"}","handlingStrategy":"type-guard","validationCode":"// Coerce/validate string fields before passing the map to the Xray builder\nfor k, v := range user {\n    if s, ok := v.(string); ok {\n        user[k] = strings.TrimSpace(s)\n    }\n}","typeGuard":"func allUserStrings(user map[string]any, keys ...string) error {\n    for _, k := range keys {\n        if v, ok := user[k]; ok && v != nil {\n            if _, isStr := v.(string); !isStr {\n                return fmt.Errorf(\"field %q must be a string, got %T\", k, v)\n            }\n        }\n    }\n    return nil\n}","tryCatchPattern":"if strings.Contains(err.Error(), \"invalid type for user field\") {\n    // %T in message names the actual type; fix producer serialization, no retry\n}","preventionTips":["Always marshal client settings from typed structs (or Zod-validated JSON), never from loosely-typed maps.","Quote numeric-looking identifiers (IDs, keepAlive) in client JSON."],"tags":["xray","type-guard","serialization"],"backgroundTag":null,"analyzedSha":"ad32144c42455696ea9f14e12168beac3e25f5d2","analyzedAt":"2026-08-15T11:13:23.905Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}