apple/pkl · error · DecodeException

unhandledMessageCode

unhandledMessageCode

Error message

unhandledMessageCode

What it means

decodeMessage returned null for a recognized message type, meaning the concrete decoder subclass does not implement handling for that message code. The decoder treats this as a protocol gap and throws unhandledMessageCode with the hex code.

Source

Thrown at pkl-core/src/main/java/org/pkl/core/messaging/AbstractMessagePackDecoder.java:82

      throw new DecodeException(ErrorMessages.create("malformedMessageHeaderException"), e);
    }

    Type msgType;
    try {
      msgType = Type.fromInt(code);
    } catch (IllegalArgumentException e) {
      throw new DecodeException(
          ErrorMessages.create("malformedMessageHeaderUnrecognizedCode", Integer.toHexString(code)),
          e);
    }

    try {
      var map = unpacker.unpackValue().asMapValue().map();
      var decoded = decodeMessage(msgType, map);
      if (decoded != null) {
        return decoded;
      }
      throw new DecodeException(
          ErrorMessages.create("unhandledMessageCode", Integer.toHexString(code)));
    } catch (MessageTypeException | URISyntaxException e) {
      throw new DecodeException(ErrorMessages.create("malformedMessageBody", code), e);
    }
  }

  protected static @Nullable Value getNullable(Map<Value, Value> map, String key) {
    return map.get(new ImmutableStringValueImpl(key));
  }

  protected static Value get(Map<Value, Value> map, String key) throws DecodeException {
    var value = map.get(new ImmutableStringValueImpl(key));
    if (value == null) {
      throw new DecodeException(ErrorMessages.create("missingMessageParameter", key));
    }
    return value;
  }

View on GitHub (pinned to f3efcbfc9b)

Solutions

  1. Implement a decodeMessage branch for the reported message type
  2. Override decodeMessage to skip (return a no-op message) instead of null for ignorable types
  3. Filter the stream upstream to drop unhandled message codes
  4. Update to a decoder version that covers all message types

Example fix

// before
case CAN_EVALUATE -> null; // falls through to unhandledMessageCode
// after
case CAN_EVALUATE -> decodeCanEvaluate(map); // implement or explicitly skip
Defensive patterns

Strategy: fallback

Try / catch

try { return decoder.decode(unpacker); } catch (DecodeException e) { if (String.valueOf(e.getMessage()).contains("unhandledMessageCode")) { return MessageSkip.INSTANCE; /* or rethrow */ } throw e; }

Prevention

When it happens

Trigger: A Type is recognized by Type.fromInt but decodeMessage(msgType, map) has no case for it and returns null.

Common situations: Custom or partial decoder implementations missing handlers for some message types (e.g. LogMessage, WarningMessage); base-class users decoding streams that include control messages they didn't implement.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08). Data as JSON: /api/errors/4aadd53c3131cd5a. Report an issue: GitHub.