apache/seatunnel · error · UnsupportedOperationException

'%s' source don't support off-line job.

Error message

'%s' source don't support off-line job.

What it means

Thrown by FactoryUtil.ensureJobModeMatch when a BATCH-mode job is configured to use a source whose Boundedness is UNBOUNDED (streaming-only). The library validates that the declared job mode matches the source's capabilities before creating the source reader, since an unbounded source can never finish a batch job.

Source

Thrown at seatunnel-api/src/main/java/org/apache/seatunnel/api/table/factory/FactoryUtil.java:491

        }
        try {
            virtualCreator.accept(factory.get());
        } catch (Exception e) {
            if (e instanceof UnsupportedOperationException
                    && "The Factory has not been implemented and the deprecated Plugin will be used."
                            .equals(e.getMessage())) {
                return true;
            }
            log.debug(ExceptionUtils.getMessage(e));
        }
        return false;
    }

    public static void ensureJobModeMatch(JobContext jobContext, SeaTunnelSource source) {
        if (jobContext.getJobMode() == JobMode.BATCH
                && source.getBoundedness()
                        == org.apache.seatunnel.api.source.Boundedness.UNBOUNDED) {
            throw new UnsupportedOperationException(
                    String.format(
                            "'%s' source don't support off-line job.", source.getPluginName()));
        }
    }
}

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Switch the job to streaming: set env { job.mode = "STREAMING" } in the config.
  2. Replace the source with a bounded connector that supports batch mode (e.g. JDBC, file, FakeSource).
  3. If the connector supports both, configure its startup/stop mode so it reports Boundedness.BOUNDED (e.g. Kafka consumer with a stop offset / specific timestamp).
  4. Check the connector documentation for which job modes its factory supports before submitting.

Example fix

// before
env { job.mode = "BATCH" }
source { Kafka { ... } }
// after
env { job.mode = "STREAMING" }
source { Kafka { ... } }
Defensive patterns

Strategy: validation

Validate before calling

if (jobContext.getJobMode() == JobMode.BATCH && source.getBoundedness() == Boundedness.UNBOUNDED) { throw new IllegalArgumentException("use STREAMING mode or a bounded source"); }

Type guard

boolean supportsBatch = source.getBoundedness() == Boundedness.BOUNDED;

Prevention

When it happens

Trigger: Calling SeaTunnelSource/FactoryUtil source creation path with a JobContext whose jobMode is JobMode.BATCH while source.getBoundedness() returns Boundedness.UNBOUNDED — e.g. running a Kafka/CDC source in a batch config ('env { job.mode = "BATCH" }') via a factory that only exposes the unbounded variant.

Common situations: Users write a batch-mode HOCON config but pick a streaming-only connector (Kafka, CDC/MySQL binlog, Pulsar stream); or upgrade a connector that changed its default boundedness; or reuse a streaming job template and only change job.mode to BATCH.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10). Data as JSON: /api/errors/28c79b073ffc6514. Report an issue: GitHub.