apache/seatunnel · error · IllegalArgumentException
Invalid jobId for trace file path: ${jobId}
Error message
Invalid jobId for trace file path: ${jobId} What it means
TraceFileWriter writes job event trace files under {baseDir}/traces/{jobId}/{date}/. To prevent path injection, the jobId must match a strict JOB_ID_PATTERN (UUID-like) before it is used in the path; a null or malformed jobId throws this IllegalArgumentException at construction time.
Source
Thrown at seatunnel-engine/seatunnel-engine-server/src/main/java/org/apache/seatunnel/engine/server/event/TraceFileWriter.java:54
import java.util.regex.Pattern;
/** Writes OTLP JSON lines into per-job trace files and rotates them based on count or size. */
@Slf4j
public class TraceFileWriter implements Closeable {
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH-mm-ss");
private static final Pattern JOB_ID_PATTERN = Pattern.compile("[a-zA-Z0-9_-]+");
private final String jobId;
private final String date;
private final Path filePath;
private final BufferedWriter writer;
private final AtomicLong eventCount;
private final AtomicLong fileSize;
private final AtomicBoolean closed = new AtomicBoolean(false);
public TraceFileWriter(String baseDir, String jobId, String date) throws IOException {
if (jobId == null || !JOB_ID_PATTERN.matcher(jobId).matches()) {
throw new IllegalArgumentException("Invalid jobId for trace file path: " + jobId);
}
this.jobId = jobId;
this.date = date;
this.eventCount = new AtomicLong(0);
this.fileSize = new AtomicLong(0);
// Create directory: {baseDir}/traces/{jobId}/{date}/
Path basePath = Paths.get(baseDir).toAbsolutePath().normalize();
Path traceDir = basePath.resolve(Paths.get("traces", jobId, date)).normalize();
if (!traceDir.startsWith(basePath)) {
throw new IllegalArgumentException("Resolved trace path escapes baseDir: " + traceDir);
}
Files.createDirectories(traceDir);
// Generate file name: traces-{HH-mm-ss}-{uuid}.jsonl
String timestamp = LocalDateTime.now().format(TIME_FORMATTER);
String shortUuid = UUID.randomUUID().toString().substring(0, 8);
String fileName = String.format("traces-%s-%s.jsonl", timestamp, shortUuid);View on GitHub (pinned to cf67b549a7)
Solutions
- Ensure the job has a valid engine-assigned jobId (UUID format) before creating the writer
- Validate/sanitize the jobId string with a UUID/regex check before constructing TraceFileWriter
- Fix event listener wiring so trace writers are only created after job initialization
- Never pass raw user input as jobId; generate or look up the engine id
Example fix
// before
new TraceFileWriter(baseDir, request.getJobId(), date); // may be arbitrary
// after
String jobId = request.getJobId();
if (jobId != null && jobId.matches("[a-fA-F0-9-]{32,36}")) {
new TraceFileWriter(baseDir, jobId, date);
} Defensive patterns
Strategy: validation
Validate before calling
if (jobId == null || !jobId.matches("[0-9a-fA-F-]{32,36}")) { throw new IllegalArgumentException("jobId must be engine-assigned UUID"); } Type guard
boolean isValidJobId(String id) { return id != null && id.matches("[0-9a-fA-F-]{32,36}"); } Try / catch
try { writer = new TraceFileWriter(baseDir, jobId, date); } catch (IllegalArgumentException e) { if (e.getMessage().startsWith("Invalid jobId")) { log.warn("skipping trace writer for invalid jobId"); } else { throw e; } } Prevention
- Only use engine-generated jobIds
- Validate identifiers before constructing writers
- Don't pass user-controlled strings as jobIds
When it happens
Trigger: Constructing TraceFileWriter with jobId=null; passing a jobId containing slashes, '..', or other characters outside the expected pattern; wiring event job status events with an unset job id.
Common situations: Custom event listeners built before jobId assignment; manually passing user-controlled job identifiers; misconfigured job event listeners forwarding placeholder ids.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- ${CONNECTOR_JAR_HA_STORAGE_TYPE} must in [localfile, hdfs]
- The Jar package file for the connector is empty!
- intervalMs must be positive, got: %s
- The physical plan didn't have any can execute pipeline
- Resolved trace path escapes baseDir: ${traceDir}
AI-assisted analysis of apache/seatunnel@cf67b549a7 (2026-09-10).
Data as JSON: /api/errors/40ec939e83475e79.
Report an issue: GitHub.