apereo/cas · error · IOException

Deserialization error

Error message

Deserialization error

What it means

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.

Solutions

  1. Ensure all CAS nodes share identical cas.webflow.crypto encryption/signing key and secret values
  2. Force the user's flow to restart (clear the webflow session/cookie) since old keys cannot recover old state
  3. Verify compression setting matches how the payload was written by the transcoder's counterpart encode()
  4. Check for serialVersionUID/classpath changes after an upgrade and redeploy consistent artifacts server-side
  5. Enable debug logging of the underlying cause (already logged via LoggingUtils) to identify cipher vs stream failure

Example fix

// before (cluster node with wrong key)
cas.webflow.crypto.encryption.key=OLD_KEY
// after
 cas.webflow.crypto.encryption.key=<same key on every node>
Defensive patterns

Strategy: try-catch

Validate before calling

// before decode
if (bytes == null || bytes.length == 0) throw new IllegalArgumentException("Empty webflow state");

Try / catch

try {
    Object state = transcoder.decode(bytes);
} catch (IOException e) {
    logger.warn("Webflow state unusable (key mismatch or corrupt); restarting flow", e);
    // discard execution key and restart the login flow
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/76bc9abf14a764ac. Report an issue: GitHub.

Appendix: source

Thrown at core/cas-server-core-webflow-api/src/main/java/org/apereo/cas/web/flow/executor/EncryptedTranscoder.java:70

                LoggingUtils.warn(LOGGER, e);
            }
            return encrypt(outBuffer);
        }
    }


    @Override
    @SuppressWarnings("BanSerializableRead")
    public Object decode(final byte[] encoded) throws IOException {
        val data = decrypt(encoded);
        try (val inBuffer = new ByteArrayInputStream(data);
             val in = this.compression
                 ? new ObjectInputStream(new GZIPInputStream(inBuffer))
                 : new ObjectInputStream(inBuffer)) {
            return in.readObject();
        } catch (final Exception e) {
            LoggingUtils.error(LOGGER, e);
            throw new IOException("Deserialization error", e);
        }
    }

    @SuppressWarnings("BanSerializableRead")
    protected void writeObjectToOutputStream(final Object o, final ObjectOutputStream out) throws IOException {
        var object = o;
        if (AopUtils.isAopProxy(o)) {
            try {
                object = ((Advised) o).getTargetSource().getTarget();
            } catch (final Exception e) {
                LoggingUtils.error(LOGGER, e);
            }
            if (object == null) {
                LOGGER.error("Could not determine object [{}] from proxy",
                    Objects.requireNonNull(o).getClass().getSimpleName());
            }
        }
        if (object != null) {

View on GitHub (pinned to e7288fc434)