apache/seatunnel · error · ClickhouseConnectorException

sourcePath is null

Error message

sourcePath is null

What it means

RsyncFileTransfer.transferAndChown(List<String>, String) rejects a null source path list with ILLEGAL_ARGUMENT / "sourcePath is null" before iterating; each non-null entry is then transferred and ownership-changed via the single-path overload.

Source

Thrown at seatunnel-connectors-v2/connector-clickhouse/src/main/java/org/apache/seatunnel/connectors/seatunnel/clickhouse/sink/file/RsyncFileTransfer.java:168

        command.add("ls");
        command.add("-l");
        command.add(
                targetPath.substring(0, StringUtils.stripEnd(targetPath, "/").lastIndexOf("/"))
                        + "/");
        command.add("| tail -n 1 | awk '{print $3}' | xargs -t -i chown -R {}:{} " + targetPath);
        try {
            String finalCommand = String.join(" ", command);
            log.info("execute remote command: " + finalCommand);
            clientSession.executeRemoteCommand(finalCommand);
        } catch (IOException e) {
            // always return error cause xargs return shell command result
        }
    }

    @Override
    public void transferAndChown(List<String> sourcePaths, String targetPath) {
        if (sourcePaths == null) {
            throw new ClickhouseConnectorException(
                    CommonErrorCodeDeprecated.ILLEGAL_ARGUMENT, "sourcePath is null");
        }
        sourcePaths.forEach(sourcePath -> transferAndChown(sourcePath, targetPath));
    }

    @Override
    public void close() {
        if (clientSession != null && clientSession.isOpen()) {
            try {
                clientSession.close();
            } catch (IOException e) {
                throw new ClickhouseConnectorException(
                        ClickhouseConnectorErrorCode.SSH_OPERATION_FAILED,
                        "Failed to close ssh session",
                        e);
            }
        }
        if (sshClient != null && sshClient.isOpen()) {

View on GitHub (pinned to cf67b549a7)

Solutions

  1. Ensure the caller passes a non-null list; skip the transfer when no files were generated (use an empty list instead of null)
  2. Initialize the source path list at declaration so it can never be null
  3. Guard call sites: only invoke transferAndChown when generated file collection succeeded

Example fix

// before
transfer.transferAndChown(clickhouseLocalFiles, targetPath); // may be null
// after
if (clickhouseLocalFiles != null && !clickhouseLocalFiles.isEmpty()) {
    transfer.transferAndChown(clickhouseLocalFiles, targetPath);
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (sourcePaths == null || sourcePaths.isEmpty()) return; // skip transfer

Type guard

if (sourcePaths == null || sourcePaths.stream().anyMatch(Objects::isNull)) {
    throw new IllegalArgumentException("sourcePaths must be a non-null list of non-null paths");
}

Prevention

When it happens

Trigger: Calling transferAndChown with a null List<String> of source paths — e.g. an upstream flush step passing null after file generation failed instead of skipping the transfer.

Common situations: Programmatic use of the file transfer API where the caller builds the path list from an operation that returned null; a failed prepareCommit still invoking transfer with an uninitialized list.

Related errors


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