{"record":{"id":"d5a96afbe778e17e","repo":"zitadel/zitadel","slug":"cannot-decode-empty-data","errorCode":null,"errorMessage":"cannot decode, empty data","messagePattern":"cannot decode, empty data","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/crypto/rsa.go","lineNumber":209,"sourceCode":"\tvar zero T\n\tif len(priv) == 0 {\n\t\treturn zero, ErrEmpty\n\t}\n\tblock, _ := pem.Decode(priv)\n\tif block == nil {\n\t\treturn zero, ErrEmpty\n\t}\n\tkey, err := x509.ParsePKCS8PrivateKey(block.Bytes)\n\tif err != nil {\n\t\treturn zero, err\n\t}\n\tif k, ok := key.(T); ok {\n\t\treturn k, nil\n\t}\n\treturn zero, zerrors.ThrowInvalidArgumentf(nil, \"CRYP-9n2s3\", \"wrong type: expected %T, got %T\", zero, key)\n}\n\nvar ErrEmpty = errors.New(\"cannot decode, empty data\")\nvar ErrNoPublicKey = errors.New(\"unsupported public key type\")\n\nfunc BytesToPublicKey(pub []byte) (crypto.PublicKey, error) {\n\tif len(pub) == 0 {\n\t\treturn nil, ErrEmpty\n\t}\n\tblock, _ := pem.Decode(pub)\n\tif block == nil {\n\t\treturn nil, ErrEmpty\n\t}\n\tkey, err := x509.ParsePKIXPublicKey(block.Bytes)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tswitch key.(type) {\n\tcase *rsa.PublicKey,\n\t\t*ecdsa.PublicKey,\n\t\ted25519.PublicKey:","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/zitadel/zitadel/blob/13948f2bcd6f257794dbd6d342c2ac30bc88fe54/internal/crypto/rsa.go#L191-L227","documentation":"ErrEmpty in internal/crypto/rsa.go is returned by the key-decoding helpers (e.g. BytesToPublicKey, BytesToPrivateKeyPKCS8) when the input byte slice is empty (len == 0). ZITADEL cannot decode an empty buffer into a key, so it fails fast with this sentinel error instead of a PEM parse error. It surfaces as an invalid-argument error in higher layers.","triggerScenarios":"Calling BytesToPublicKey/BytesToPrivateKeyPKCS8 with a zero-length []byte; command layer (instance_idp/org_idp) adding a generic/machine IDP with an empty private key blob, mapped to INST-Fk38d / ORG-Fk38d 'Errors.IDP.InvalidPrivateKey'.","commonSituations":"Uploading a generic OIDC/JWT IDP config where the private key file was empty or not read; generating a key into a variable that was never populated; test fixtures passing empty key data.","solutions":["Ensure the private key bytes are actually loaded before calling the API — read the key file and check len(data) > 0","Regenerate the signing key (e.g. openssl genpkey ...) and re-upload it","In tests, supply a valid non-empty PEM-encoded RSA key in the Key payload","Validate input in your client code before the call: if len(key) == 0 { return error }"],"exampleFix":"// before\nkeyData, _ := os.ReadFile(cfg.KeyFile) // silently empty on error\n// after\nkeyData, err := os.ReadFile(cfg.KeyFile)\nif err != nil || len(keyData) == 0 {\n    return fmt.Errorf(\"IDP private key missing or empty: %w\", err)\n}","handlingStrategy":"validation","validationCode":"if len(privateKeyPEM) == 0 {\n    return errors.New(\"IDP private key is empty\")\n}","typeGuard":"func hasKeyData(b []byte) bool { return len(b) > 0 && bytes.HasPrefix(bytes.TrimSpace(b), []byte(\"-----BEGIN\")) }","tryCatchPattern":"if err := idp.AddGenericOIDC(ctx, ...); errors.Is(err, crypto.ErrEmpty) {\n    return fmt.Errorf(\"IDP private key missing/empty: %w\", err)\n}","preventionTips":["Read key files with error handling; never ignore the error from os.ReadFile","Validate key material (non-empty, PEM-prefixed) before submitting IDP config","Keep test fixtures with real generated keys, not empty placeholders"],"tags":["go","crypto","rsa","empty-input"],"backgroundTag":"empty-required-field","analyzedSha":"13948f2bcd6f257794dbd6d342c2ac30bc88fe54","analyzedAt":"2026-09-06T10:16:19.814Z","contentChangedAt":"2026-09-06T10:16:19.814Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}