{"record":{"id":"f30cec4dc9544d46","repo":"cloudflare/cloudflared","slug":"unable-to-marshal-tunnel-credentials-to-json","errorCode":null,"errorMessage":"Unable to marshal tunnel credentials to JSON","messagePattern":"Unable to marshal tunnel credentials to JSON","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/cloudflared/tunnel/subcommands.go","lineNumber":310,"sourceCode":"\nfunc tunnelFilePath(tunnelID uuid.UUID, directory string) (string, error) {\n\tfileName := fmt.Sprintf(\"%v.json\", tunnelID)\n\tfilePath := filepath.Clean(fmt.Sprintf(\"%s/%s\", directory, fileName))\n\treturn homedir.Expand(filePath)\n}\n\n// writeTunnelCredentials saves `credentials` as a JSON into `filePath`, only if\n// the file does not exist already\nfunc writeTunnelCredentials(filePath string, credentials *connection.Credentials) error {\n\tif _, err := os.Stat(filePath); !os.IsNotExist(err) {\n\t\tif err == nil {\n\t\t\treturn fmt.Errorf(\"%s already exists\", filePath)\n\t\t}\n\t\treturn err\n\t}\n\tbody, err := json.Marshal(credentials)\n\tif err != nil {\n\t\treturn errors.Wrap(err, \"Unable to marshal tunnel credentials to JSON\")\n\t}\n\treturn os.WriteFile(filePath, body, 0400)\n}\n\nfunc buildListCommand() *cli.Command {\n\treturn &cli.Command{\n\t\tName:        \"list\",\n\t\tAction:      cliutil.ConfiguredAction(listCommand),\n\t\tUsage:       \"List existing tunnels\",\n\t\tUsageText:   \"cloudflared tunnel [tunnel command options] list [subcommand options]\",\n\t\tDescription: \"cloudflared tunnel list will display all active tunnels, their created time and associated connections. Use -d flag to include deleted tunnels. See the list of options to filter the list\",\n\t\tFlags: []cli.Flag{\n\t\t\toutputFormatFlag,\n\t\t\tshowDeletedFlag,\n\t\t\tlistNameFlag,\n\t\t\tlistNamePrefixFlag,\n\t\t\tlistExcludeNamePrefixFlag,\n\t\t\tlistExistedAtFlag,","sourceCodeStart":292,"sourceCodeEnd":328,"githubUrl":"https://github.com/cloudflare/cloudflared/blob/2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f/cmd/cloudflared/tunnel/subcommands.go#L292-L328","documentation":"writeTunnelCredentials marshals the tunnel's credentials struct to JSON before writing it to <tunnelID>.json with 0400 permissions. json.Marshal on this struct should never fail in practice, so this error indicates an internal serialization problem (e.g. an unsupported or corrupt field value in the credentials object).","triggerScenarios":"Called from create and tokenCommand when the Credentials struct returned by the tunnel-creation API or token parsing contains a value Go's encoding/json cannot marshal (nominally only for unsupported types like channels, funcs, or cyclic data).","commonSituations":"Practically rare — it can surface after code modifications introducing a non-serializable field to the credentials struct, or from corrupted in-memory credential state in custom builds/patches of cloudflared.","solutions":["Read the wrapped json.Marshal error for the exact field that failed to serialize","Update cloudflared to the latest release; this indicates a bug in the version you are running","If running a custom patch, remove non-JSON-serializable fields from the tunnel credentials struct","Retry the create/token command to rule out transient corrupted state"],"exampleFix":"// before (custom build)\ntype Credentials struct { Conn func() } // unsupported type\n// after\ntype Credentials struct { AccountTag, TunnelSecret, TunnelID string }","handlingStrategy":"type-guard","validationCode":"func credentialsSerializable(c Credentials) error {\n\tv := reflect.ValueOf(c)\n\tfor i := 0; i < v.NumField(); i++ {\n\t\tif !v.Field(i).CanInterface() { continue }\n\t\tswitch v.Field(i).Kind() {\n\t\tcase reflect.Chan, reflect.Func, reflect.UnsafePointer:\n\t\t\treturn fmt.Errorf(\"field %s not JSON-serializable\", v.Type().Field(i).Name)\n\t\t}\n\t}\n\treturn nil\n}","typeGuard":"func isMarshalable(v any) bool {\n\t_, err := json.Marshal(v)\n\treturn err == nil\n}","tryCatchPattern":"body, err := json.Marshal(credentials)\nif err != nil {\n\treturn fmt.Errorf(\"Unable to marshal tunnel credentials to JSON: %w\", err)\n}","preventionTips":["Keep the Credentials struct limited to string fields","Add a unit test marshaling the credentials struct on every struct change","Pin and update cloudflared versions; treat this error as a bug report","Validate credentials round-trip (marshal then unmarshal) in CI"],"tags":["cloudflared","json","serialization","credentials"],"backgroundTag":"json-marshal-failed","analyzedSha":"2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f","analyzedAt":"2026-09-06T04:14:33.757Z","contentChangedAt":"2026-09-06T04:14:33.757Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}