{"record":{"id":"c0e4f3ef7c50a8ac","repo":"kubernetes/kops","slug":"failed-to-marshal-token-w-c0e4f3","errorCode":null,"errorMessage":"failed to marshal token: %w","messagePattern":"failed to marshal token: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/gce/tpm/gcetpmsigner/tpmauthenticator.go","lineNumber":112,"sourceCode":"\t}\n\n\tpayload, err := json.Marshal(&data)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to marshal token data: %w\", err)\n\t}\n\n\tsignature, err := tpmSign(key, payload)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to sign token data: %w\", err)\n\t}\n\ttoken := &gcetpm.AuthToken{\n\t\tData:      payload,\n\t\tSignature: signature,\n\t}\n\n\tb, err := json.Marshal(token)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to marshal token: %w\", err)\n\t}\n\treturn gcetpm.GCETPMAuthenticationTokenPrefix + base64.StdEncoding.EncodeToString(b), nil\n}\n\n// tpmSign performs a TPM signature with the tpmKey, and sanity checks the result.\nfunc tpmSign(tpmKey *client.Key, payload []byte) ([]byte, error) {\n\tbeforeSign := time.Now()\n\tsignature, err := tpmKey.SignData(payload)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to sign data with TPM: %w\", err)\n\t}\n\n\tklog.Infof(\"TPM signing took %v\", time.Since(beforeSign))\n\n\treturn signature, nil\n}\n\nfunc debugToPEM(key crypto.PublicKey) string {","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/gce/tpm/gcetpmsigner/tpmauthenticator.go#L94-L130","documentation":"After signing, CreateToken marshals the gcetpm.AuthToken {Data, Signature} struct to JSON before base64-encoding it into the final prefixed token string. This wraps a json.Marshal failure of the AuthToken. Like the payload marshal, it should never fire for these byte-slice fields and signals a code-level problem.","triggerScenarios":"json.Marshal(token) returns an error — only via a faulty custom MarshalJSON on AuthToken or an unsupported field type introduced in the struct.","commonSituations":"Refactors that add non-serializable fields or a broken MarshalJSON to gcetpm.AuthToken; version skew between vendored gcetpm package copies.","solutions":["Inspect the wrapped error for the failing field","Fix/remove custom MarshalJSON on gcetpm.AuthToken","Keep Data and Signature as []byte (correct base64-encodable JSON types)","Ensure both node (signer) and server (verifier) use the same gcetpm package version"],"exampleFix":"null","handlingStrategy":"try-catch","validationCode":"if _, err := json.Marshal(gcetpm.AuthToken{}); err != nil {\n    // schema regression detected in tests\n    panic(err)\n}","typeGuard":null,"tryCatchPattern":"token, err := authenticator.CreateToken(ctx, request)\nif err != nil && strings.Contains(err.Error(), \"failed to marshal token\") {\n    return fmt.Errorf(\"token schema regression: %w\", err)\n}","preventionTips":["Unit-test full token round-trip: CreateToken then VerifyToken on both sides","Keep AuthToken fields as []byte","Use a shared gcetpm package import for signer and verifier"],"tags":["json","serialization","gce","tpm"],"backgroundTag":"json-marshal-failed","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}