{"record":{"id":"76bc9abf14a764ac","repo":"apereo/cas","slug":"deserialization-error","errorCode":null,"errorMessage":"Deserialization error","messagePattern":"Deserialization error","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"core/cas-server-core-webflow-api/src/main/java/org/apereo/cas/web/flow/executor/EncryptedTranscoder.java","lineNumber":70,"sourceCode":"                LoggingUtils.warn(LOGGER, e);\n            }\n            return encrypt(outBuffer);\n        }\n    }\n\n\n    @Override\n    @SuppressWarnings(\"BanSerializableRead\")\n    public Object decode(final byte[] encoded) throws IOException {\n        val data = decrypt(encoded);\n        try (val inBuffer = new ByteArrayInputStream(data);\n             val in = this.compression\n                 ? new ObjectInputStream(new GZIPInputStream(inBuffer))\n                 : new ObjectInputStream(inBuffer)) {\n            return in.readObject();\n        } catch (final Exception e) {\n            LoggingUtils.error(LOGGER, e);\n            throw new IOException(\"Deserialization error\", e);\n        }\n    }\n\n    @SuppressWarnings(\"BanSerializableRead\")\n    protected void writeObjectToOutputStream(final Object o, final ObjectOutputStream out) throws IOException {\n        var object = o;\n        if (AopUtils.isAopProxy(o)) {\n            try {\n                object = ((Advised) o).getTargetSource().getTarget();\n            } catch (final Exception e) {\n                LoggingUtils.error(LOGGER, e);\n            }\n            if (object == null) {\n                LOGGER.error(\"Could not determine object [{}] from proxy\",\n                    Objects.requireNonNull(o).getClass().getSimpleName());\n            }\n        }\n        if (object != null) {","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/core/cas-server-core-webflow-api/src/main/java/org/apereo/cas/web/flow/executor/EncryptedTranscoder.java#L52-L88","documentation":"EncryptedTranscoder.decode wraps all failures during decryption, decompression, and ObjectInputStream.readObject into a generic IOException(\"Deserialization error\"). CAS uses this transcoder to decrypt/deserialize the webflow session state carried in the execution parameter, so any corruption, wrong cipher key, or incompatible serialized class fails here.","triggerScenarios":"Calling decode() on a byte buffer whose ciphertext was encrypted with a different cas.webflow crypto key/secret, or whose payload is not GZIP-compressed while this.compression is true, or whose serialized classes are missing/changed (InvalidClassException, ClassNotFoundException), or truncated input.","commonSituations":"Rotating or mismatching cas.webflow.crypto.encryption.key/signing.key across nodes in a cluster; upgrading CAS so serialized flow-session classes changed serialVersionUID; load balancer sending the flowExecutionKey to a server with different crypto config; cookie/storage truncation.","solutions":["Ensure all CAS nodes share identical cas.webflow.crypto encryption/signing key and secret values","Force the user's flow to restart (clear the webflow session/cookie) since old keys cannot recover old state","Verify compression setting matches how the payload was written by the transcoder's counterpart encode()","Check for serialVersionUID/classpath changes after an upgrade and redeploy consistent artifacts server-side","Enable debug logging of the underlying cause (already logged via LoggingUtils) to identify cipher vs stream failure"],"exampleFix":"// before (cluster node with wrong key)\ncas.webflow.crypto.encryption.key=OLD_KEY\n// after\n cas.webflow.crypto.encryption.key=<same key on every node>","handlingStrategy":"try-catch","validationCode":"// before decode\nif (bytes == null || bytes.length == 0) throw new IllegalArgumentException(\"Empty webflow state\");","typeGuard":null,"tryCatchPattern":"try {\n    Object state = transcoder.decode(bytes);\n} catch (IOException e) {\n    logger.warn(\"Webflow state unusable (key mismatch or corrupt); restarting flow\", e);\n    // discard execution key and restart the login flow\n}","preventionTips":["Keep cas.webflow.crypto keys identical across all cluster nodes","Restart the flow rather than retrying decode of stale state","After CAS upgrades, expect old flow executions to fail and force re-login","Verify compression settings symmetric between encode/decode"],"tags":["deserialization","java-io","webflow","session-state"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}