apache/pulsar · error · IllegalArgumentException

Sink timeout must be a positive number

Error message

Sink timeout must be a positive number

What it means

If the sink config sets a timeoutMs, it must be non-negative (the message says 'positive', the check rejects negative values; null means no timeout). validateAndExtractDetails throws IllegalArgumentException when timeoutMs < 0.

Source

Thrown at pulsar-functions/utils/src/main/java/org/apache/pulsar/functions/utils/SinkConfigUtils.java:455

            }
        }
        if (!isEmpty(sinkConfig.getLogTopic())) {
            if (!TopicName.isValid(sinkConfig.getLogTopic())) {
                throw new IllegalArgumentException(
                        String.format("LogTopic topic %s is invalid", sinkConfig.getLogTopic()));
            }
        }

        if (sinkConfig.getParallelism() != null && sinkConfig.getParallelism() <= 0) {
            throw new IllegalArgumentException("Sink parallelism must be a positive number");
        }

        if (sinkConfig.getResources() != null) {
            ResourceConfigUtils.validate(sinkConfig.getResources());
        }

        if (sinkConfig.getTimeoutMs() != null && sinkConfig.getTimeoutMs() < 0) {
            throw new IllegalArgumentException("Sink timeout must be a positive number");
        }

        String sinkClassName = sinkConfig.getClassName();
        // if class name in sink config is not set, this should be a built-in sink
        // thus we should try to find it class name in the NAR service definition
        if (sinkClassName == null) {
            ConnectorDefinition connectorDefinition = sinkFunction.getFunctionMetaData(ConnectorDefinition.class);
            if (connectorDefinition == null) {
                throw new IllegalArgumentException(
                        "Sink package doesn't contain the META-INF/services/pulsar-io.yaml file.");
            }
            sinkClassName = connectorDefinition.getSinkClass();
            if (sinkClassName == null) {
                throw new IllegalArgumentException("Failed to extract sink class from archive");
            }
        }

        // check if sink implements the correct interfaces

View on GitHub (pinned to 820761864e)

Solutions

  1. Set a non-negative timeout in milliseconds, e.g. sinkConfig.setTimeoutMs(30000L).
  2. To disable the timeout, leave timeoutMs unset (null) instead of -1.
  3. Fix duration computation that underflows to a negative value.
  4. Validate timeout >= 0 before submitting.

Example fix

// before
sinkConfig.setTimeoutMs(-1L); // intended 'disabled'
// after
// leave unset to disable:
// sinkConfig.setTimeoutMs(null); — or set a real value:
sinkConfig.setTimeoutMs(30000L);
Defensive patterns

Strategy: validation

Validate before calling

if (sinkConfig.getTimeoutMs() != null && sinkConfig.getTimeoutMs() < 0) {
    throw new IllegalArgumentException("timeoutMs must be >= 0");
}

Type guard

static boolean hasValidTimeout(SinkConfig cfg) {
    return cfg.getTimeoutMs() == null || cfg.getTimeoutMs() >= 0;
}

Try / catch

try {
    SinkConfigUtils.validateAndExtractDetails(cfg, sinkPkg, transformPkg, true);
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("timeout")) {
        log.error("Negative sink timeoutMs: {}", cfg.getTimeoutMs(), e);
    }
    throw e;
}

Prevention

When it happens

Trigger: SinkConfig.setTimeoutMs(-1) — often from using -1 as a sentinel 'disabled' value in code or config, or an arithmetic underflow when computing the timeout.

Common situations: Users setting '-1' to disable ack timeout based on other systems' conventions; duration parsing producing negative values; copy-pasted config from tools where -1 means infinite.

Understand the failure class

Background: "must be positive", "Invalid value": how libraries reject invalid parameter values (ValueError, ArgumentError, INVALID_PARAMETER_VALUE) — this error's family across 28 libraries.

Related errors


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