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

  1. Ensure the job has a valid engine-assigned jobId (UUID format) before creating the writer
  2. Validate/sanitize the jobId string with a UUID/regex check before constructing TraceFileWriter
  3. Fix event listener wiring so trace writers are only created after job initialization
  4. 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

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


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