xpipe-io/xpipe · error · IOException

Source file ${sourceFile} input size mismatch: Expected ${ex

Error message

Source file ${sourceFile} input size mismatch: Expected ${expected} but got ${actual}. Did the source file get updated?

What it means

Thrown during transferFile when the number of bytes actually read from the source file is less than the expected file size recorded when the transfer was planned. The operation treats a short read as corruption risk and kills the streams, wrapping it in an IOException.

Source

Thrown at app/src/main/java/io/xpipe/app/browser/file/BrowserFileTransferOperation.java:622

                        killStreams.set(true);
                        break;
                    }

                    outputStream.write(buffer, 0, read);
                    transferred.addAndGet(read);
                    readCount.addAndGet(read);
                    if (reportProgress) {
                        updateProgress(
                                new BrowserTransferProgress(sourceFile.getFileName(), transferred.get(), total.get()));
                    }
                }

                outputStream.flush();
                inputStream.transferTo(OutputStream.nullOutputStream());

                var incomplete = !killStreams.get() && readCount.get() < expectedFileSize;
                if (incomplete) {
                    throw new IOException("Source file " + sourceFile + " input size mismatch: Expected "
                            + expectedFileSize + " but got " + readCount.get() + ". Did the source file get updated?");
                }
            } catch (Exception ex) {
                exception.set(ex);
                killStreams.set(true);
            }
        });

        thread.start();
        while (true) {
            var alive = thread.isAlive();
            var cancelled = cancelled();

            if (cancelled) {
                killStreams(thread, readCount, false);
                break;
            }

View on GitHub (pinned to d85ca821ba)

Solutions

  1. Retry the transfer after the source file stops changing
  2. Exclude actively written files (logs, temp files) from the transfer
  3. Snapshot/quiesce the source (stop the writer) before transferring
  4. Verify connection stability to the remote system and retry

Example fix

// before
transferFiles(List.of("/var/log/app.log")) // file being actively written
// after
// copy or rotate the log first, then transfer the static file
transferFiles(List.of("/var/log/app.log.1"))
Defensive patterns

Strategy: retry

Validate before calling

async function transferStable(transfer, files, retries = 2) {
  for (let i = 0; i <= retries; i++) {
    try { return await transfer(files); }
    catch (e) {
      if (!String(e.message).includes('size mismatch') || i === retries) throw e;
    }
  }
}

Try / catch

try {
  await transferFiles(files);
} catch (e) {
  if (String(e.message).includes('size mismatch')) {
    // source changed mid-transfer; quiesce writer and retry
  }
}

Prevention

When it happens

Trigger: The source file shrunk or was truncated/rewritten between size capture and streaming, or the underlying stream ended early (network drop, remote process writing the file concurrently).

Common situations: Transferring log files actively being rotated or truncated, files modified by a running job on the remote host, unstable SSH/network connections terminating the stream early.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


AI-assisted analysis of xpipe-io/xpipe@d85ca821ba (2026-09-06). Data as JSON: /api/errors/df6d41c349bc067b. Report an issue: GitHub.