{"record":{"id":"154cde6698daa52d","repo":"router-for-me/CLIProxyAPI","slug":"vertex-credential-merge-metadata-failed-w","errorCode":null,"errorMessage":"vertex credential: merge metadata failed: %w","messagePattern":"vertex credential: merge metadata failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/auth/vertex/vertex_credentials.go","lineNumber":66,"sourceCode":"// It ensures the parent directory exists and logs the operation for transparency.\nfunc (s *VertexCredentialStorage) SaveTokenToFile(authFilePath string) error {\n\tmisc.LogSavingCredentials(authFilePath)\n\tif s == nil {\n\t\treturn fmt.Errorf(\"vertex credential: storage is nil\")\n\t}\n\tif s.ServiceAccount == nil {\n\t\treturn fmt.Errorf(\"vertex credential: service account content is empty\")\n\t}\n\t// Ensure we tag the file with the provider type.\n\ts.Type = \"vertex\"\n\n\tif err := os.MkdirAll(filepath.Dir(authFilePath), 0o700); err != nil {\n\t\treturn fmt.Errorf(\"vertex credential: create directory failed: %w\", err)\n\t}\n\n\tdata, errMerge := misc.MergeMetadata(s, s.Metadata)\n\tif errMerge != nil {\n\t\treturn fmt.Errorf(\"vertex credential: merge metadata failed: %w\", errMerge)\n\t}\n\n\tf, err := os.Create(authFilePath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"vertex credential: create file failed: %w\", err)\n\t}\n\tdefer func() {\n\t\tif errClose := f.Close(); errClose != nil {\n\t\t\tlog.Errorf(\"vertex credential: failed to close file: %v\", errClose)\n\t\t}\n\t}()\n\tenc := json.NewEncoder(f)\n\tenc.SetIndent(\"\", \"  \")\n\tif err = enc.Encode(data); err != nil {\n\t\treturn fmt.Errorf(\"vertex credential: encode failed: %w\", err)\n\t}\n\treturn nil\n}","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/auth/vertex/vertex_credentials.go#L48-L84","documentation":"Returned by VertexCredentialStorage.SaveTokenToFile when misc.MergeMetadata fails to combine the storage struct with its Metadata map before JSON encoding (vertex_credentials.go:64-67). Like the Kimi equivalent, this is a JSON-marshal failure over the metadata — the VertexCredentialStorage or its Metadata contains values Go's encoder cannot serialize.","triggerScenarios":"Metadata map holding channels, funcs, or cyclic references; a ServiceAccount map containing unserializable Go values (rare, since it normally comes from JSON); unsupported numeric types like NaN.","commonSituations":"SDK embedders attaching runtime objects as metadata; NaN/Inf floats injected by custom accounting code; effectively unreachable via plain config-driven usage.","solutions":["Restrict Metadata entries to JSON-native types; stringify anything exotic before assignment","Inspect the wrapped cause in the error chain to find the offending key","If ServiceAccount was built programmatically, ensure it came from json.Unmarshal rather than hand-built Go values"],"exampleFix":"// before\ns.Metadata = map[string]any{\"stop\": make(chan struct{})}\n// after\ns.Metadata = map[string]any{\"stop\": \"signal-name\"}","handlingStrategy":"validation","validationCode":"if _, err := json.Marshal(s.Metadata); err != nil {\n    return fmt.Errorf(\"vertex metadata not serializable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := s.SaveTokenToFile(path); err != nil && strings.Contains(err.Error(), \"merge metadata failed\") {\n    s.Metadata = nil\n    err = s.SaveTokenToFile(path)\n}","preventionTips":["Store only JSON-native values in metadata maps","Encode exotic values to strings at assignment time","Test save with production-shaped metadata"],"tags":["json","vertex","metadata","auth"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}