apache/seatunnel · error · IllegalArgumentException
source position sourceId must not be blank
Error message
source position sourceId must not be blank
What it means
SqliteSourcePositionStore.save() validates that the EdgeSourcePosition carries a non-blank sourceId before persisting the position row. A null or whitespace-only sourceId would create an unusable position record, so the store rejects it with this IllegalArgumentException.
Solutions
- Set a non-blank sourceId on the EdgeSourcePosition before saving (e.g. position.setSourceId("my-source") or the configured source name).
- Check the source configuration so the id used to build the position is populated.
- Validate the position object in caller code before passing it to the store.
- If the position came from a serialized record, verify the source produced complete position data.
Example fix
// before
store.save(new EdgeSourcePosition(null, partition, offset, 0));
// after
store.save(new EdgeSourcePosition("kafka-source-1", partition, offset, 0)); Defensive patterns
Strategy: validation
Validate before calling
if (position.getSourceId() == null || position.getSourceId().trim().isEmpty()) { throw new IllegalStateException("sourceId required before save"); } store.save(position); Type guard
boolean hasSourceId(EdgeSourcePosition p) { return p.getSourceId() != null && !p.getSourceId().trim().isEmpty(); } Try / catch
try { store.save(position); } catch (IllegalArgumentException e) { if (e.getMessage().contains("sourceId must not be blank")) { log.error("Position missing sourceId: {}", position); } throw e; } Prevention
- Always assign the configured source name/id when building EdgeSourcePosition.
- Validate positions at source construction time, not at store time.
- Deserialize positions with schema checks so sourceId cannot be dropped.
- Use the source's stable configured id, not a runtime-generated label.
When it happens
Trigger: Calling positionStore.save(position) with EdgeSourcePosition whose getSourceId() is null or only whitespace, e.g. built via a builder without setSourceId or constructed from a config where the source id option was missing.
Common situations: A source connector was configured without an explicit id/name; deserializing a position record from an external store with missing fields; programmatic use of the store with a partially populated EdgeSourcePosition.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- source position partition must not be blank
- AmazonDocumentDB option '' must be a valid BSON/JSON…
- AmazonDocumentDB option '' must not be blank
- API-01
- At least one sink plugin must be configured.
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/d2b48672b04ec1b0.
Report an issue: GitHub.
Appendix: source
Thrown at seatunnel-edge-agent/seatunnel-edge-agent-starter/src/main/java/org/apache/seatunnel/edge/agent/starter/wal/sqlite/SqliteSourcePositionStore.java:89
try (PreparedStatement statement =
connection.prepareStatement(SourcePositionSqlStatements.SELECT_BY_SOURCE)) {
statement.setString(1, sourceId);
try (ResultSet resultSet = statement.executeQuery()) {
while (resultSet.next()) {
EdgeSourcePosition position = toPosition(resultSet);
positions.put(position.getPartition(), position);
}
}
}
return positions;
}
@Override
public void save(EdgeSourcePosition position) throws Exception {
String sourceId = position.getSourceId();
String partition = position.getPartition();
if (sourceId == null || sourceId.trim().isEmpty()) {
throw new IllegalArgumentException("source position sourceId must not be blank");
}
if (partition == null || partition.trim().isEmpty()) {
throw new IllegalArgumentException("source position partition must not be blank");
}
long updatedAt =
position.getUpdatedAt() > 0L ? position.getUpdatedAt() : System.currentTimeMillis();
try (PreparedStatement statement =
connection.prepareStatement(SourcePositionSqlStatements.UPSERT)) {
statement.setString(1, sourceId);
statement.setString(2, partition);
statement.setLong(3, position.getOffset());
statement.setBytes(4, MetadataSerde.serialize(position.getMetadata()));
statement.setLong(5, updatedAt);
statement.executeUpdate();
}
}
@OverrideView on GitHub (pinned to cf67b549a7)