apache/pulsar · error · IllegalArgumentException

The value in the record returned by the source cannot be nul

Error message

The value in the record returned by the source cannot be null

What it means

The Source returned a Record whose getValue() is null. readInput eagerly resolves the value so a malformed or poison message fails with full context (message id, topic, key, schema version) via logInputValueDecodeFailure, then rethrows. The function runtime cannot route a null value through the function, so it throws IllegalArgumentException.

Source

Thrown at pulsar-functions/instance/src/main/java/org/apache/pulsar/functions/instance/JavaInstanceRunnable.java:572

            if (stats != null) {
                stats.incrSourceExceptions(e);
            }
            log.error().exception(e).log("Encountered exception in source read");
            throw e;
        } finally {
            Thread.currentThread().setContextClassLoader(instanceClassLoader);
        }

        // check record is valid
        if (record == null) {
            throw new IllegalArgumentException("The record returned by the source cannot be null");
        }
        // Eagerly access the value here so a malformed/poison message surfaces with enough
        // context (message id, topic, key, schema version) to be located and skipped, instead
        // of bubbling up as an opaque crash that names no message.
        try {
            if (record.getValue() == null) {
                throw new IllegalArgumentException("The value in the record returned by the source cannot be null");
            }
        } catch (Exception e) {
            logInputValueDecodeFailure(record, e);
            throw e;
        }
        return record;
    }

    private void logInputValueDecodeFailure(Record<?> record, Exception e) {
        log.warn()
                .attr("topic", record.getTopicName().orElse(null))
                .attr("messageId", record.getMessage().map(m -> String.valueOf(m.getMessageId())).orElse(null))
                .attr("partitionKey", record.getKey().orElse(null))
                .attr("schemaVersion", record.getMessage()
                        .map(Message::getSchemaVersion)
                        .map(sv -> HexFormat.of().formatHex(sv))
                        .orElse(null))
                .exception(e)

View on GitHub (pinned to 820761864e)

Solutions

  1. Fix the Source or Record implementation to throw a meaningful exception (or skip the record) instead of returning null from getValue()
  2. Check the logInputValueDecodeFailure log output for topic/message-id/schema-version to locate and delete or repair the poison message
  3. If using auto schema (AUTO_CONSUME), verify the topic's schema matches the declared function input schema; a mismatch can decode to null
  4. Validate payloads at the producer side so null/empty values never reach the input topic

Example fix

// before
public String getValue() {
    try { return decode(bytes); } catch (Exception e) { return null; }
}
// after
public String getValue() {
    try { return decode(bytes); } catch (Exception e) {
        throw new RuntimeException("Cannot decode message " + getId().get(), e);
    }
}
Defensive patterns

Strategy: validation

Validate before calling

Record<String> rec = source.read();
if (rec == null || rec.getValue() == null) {
    throw new IllegalStateException("null/null-value record from source");
}

Type guard

boolean hasValue(Record<?> r) { return r != null && r.getValue() != null; }

Try / catch

try { ctx.newOutputMessage(...).value(rec.getValue()).send(); }
catch (IllegalArgumentException e) { log.error("null record value", e); /* skip */ }

Prevention

When it happens

Trigger: Record.getValue() deserialization fails and the Record implementation swallows the exception returning null; a Source constructs a Record with a null payload; a schema decode of a malformed message yields null.

Common situations: Poison messages on the input topic (invalid protobuf/avro bytes); custom Record implementations that catch decode exceptions and return null; Sources built over untyped stores where the payload is genuinely missing.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/c7688538d9f9b9f0. Report an issue: GitHub.