{"record":{"id":"11c30fcdfef144cd","repo":"fatedier/frp","slug":"field-s-cannot-unmarshal-s-into-s","errorCode":null,"errorMessage":"field \"%s\": cannot unmarshal %s into %s","messagePattern":"field \"(.+?)\": cannot unmarshal (.+?) into (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/config/load.go","lineNumber":243,"sourceCode":"\t}\n\tvar strictErr *toml.StrictMissingError\n\tif errors.As(err, &strictErr) {\n\t\treturn strictErr\n\t}\n\treturn err\n}\n\n// enhanceDecodeError tries to add field path and line number information to JSON/YAML decode errors.\nfunc enhanceDecodeError(err error, originalContent []byte, includeLine bool) error {\n\tvar typeErr *json.UnmarshalTypeError\n\tif errors.As(err, &typeErr) && typeErr.Field != \"\" {\n\t\tif includeLine {\n\t\t\tline := findFieldLineInContent(originalContent, typeErr.Field)\n\t\t\tif line > 0 {\n\t\t\t\treturn fmt.Errorf(\"line %d: field \\\"%s\\\": cannot unmarshal %s into %s\", line, typeErr.Field, typeErr.Value, typeErr.Type)\n\t\t\t}\n\t\t}\n\t\treturn fmt.Errorf(\"field \\\"%s\\\": cannot unmarshal %s into %s\", typeErr.Field, typeErr.Value, typeErr.Type)\n\t}\n\treturn err\n}\n\n// findFieldLineInContent searches the original config content for a field name\n// and returns the 1-indexed line number where it appears, or 0 if not found.\nfunc findFieldLineInContent(content []byte, fieldPath string) int {\n\tif fieldPath == \"\" {\n\t\treturn 0\n\t}\n\n\t// Use the last component of the field path (e.g. \"proxies\" from \"proxies\" or\n\t// \"protocol\" from \"transport.protocol\").\n\tparts := strings.Split(fieldPath, \".\")\n\tsearchKey := parts[len(parts)-1]\n\n\tlines := bytes.Split(content, []byte(\"\\n\"))\n\tfor i, line := range lines {","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/pkg/config/load.go#L225-L261","documentation":"The line-less variant of the type-mismatch message: the same JSON UnmarshalTypeError reached the formatter but includeLine was false (or the field could not be located in the content), so only field path, offending value, and target type are reported. It means a config field has the wrong value type, without positional info.","triggerScenarios":"Decoding frp config from sources where line mapping is not attempted — e.g. content assembled programmatically or strict-mode YAML paths that skip line lookup — and a field's value cannot be converted (string into int, object into array, etc.).","commonSituations":"Configs generated by tools/Helm templates that emit quoted numbers or wrong nesting; API-driven config assembly where the operator cannot rely on line numbers anyway.","solutions":["Use the field path in the message to locate the value manually and fix its type","If available, load the same content from a file so the line-number variant pinpoints the location","Validate generated configs against frp's JSON schema before shipping"],"exampleFix":"// before\n{ \"transport\": { \"heartbeatInterval\": \"30\" } }\n\n// after\n{ \"transport\": { \"heartbeatInterval\": 30 } }","handlingStrategy":"validation","validationCode":"// when assembling config programmatically, marshal+unmarshal through the typed struct first\nprobe := v1.ClientConfig{}\nif err := json.Unmarshal(assembled, &probe); err != nil { var te *json.UnmarshalTypeError; if errors.As(err, &te) { return fmt.Errorf(\"field %s wrong type\", te.Field) } }","typeGuard":null,"tryCatchPattern":"if err := json.Unmarshal(data, &cfg); err != nil { var te *json.UnmarshalTypeError; if errors.As(err, &te) && te.Field != \"\" { /* report field path to caller for manual location */ } }","preventionTips":["Generate configs from typed structs, not string concatenation","Validate against the schema at generation time","Log field paths in your config pipeline"],"tags":["config","json","yaml","type-conversion","parsing"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}