juicedata/juicefs · error · EOFException
position is negative
Error message
position is negative
What it means
The private positioned read read(long pos, ByteBuffer) throws EOFException("position is negative") when the requested read offset is negative. This is a caller-contract guard before issuing jfs_pread to the native library; a negative pos is meaningless for a file offset. It surfaces as java.io.EOFException, consistent with Hadoop's positioned-read conventions.
Source
Thrown at sdk/java/src/main/java/io/juicefs/JuiceFileSystemImpl.java:1170
if (got > 0) {
srcBuf.limit(srcBuf.position() + got);
b.put(srcBuf);
buf.position(srcBuf.position());
statistics.incrementBytesRead(got);
}
int more = read(position, b);
if (more <= 0)
return got > 0 ? got : -1;
position += more;
statistics.incrementBytesRead(more);
buf.position(0);
buf.limit(0);
return got + more;
}
private synchronized int read(long pos, ByteBuffer b) throws IOException {
if (pos < 0)
throw new EOFException("position is negative");
if (!b.hasRemaining())
return 0;
int got;
int startPos = b.position();
got = lib.jfs_pread(Thread.currentThread().getId(), fd, b, b.remaining(), pos);
if (got == EINVAL)
throw new IOException("stream was closed");
if (got < 0)
throw error(got, path);
if (got == 0)
return -1;
b.position(startPos + got);
return got;
}
@Override
public synchronized void seek(long p) throws IOException {
if (p < 0) {View on GitHub (pinned to c9a67b23e8)
Solutions
- Clamp the offset: pos = Math.max(0, pos) before calling read(pos, ...).
- Fix the position arithmetic that produced the negative value (check seek/skip calculations).
- Validate any user- or metadata-supplied offset before passing it to positioned reads.
Example fix
// before in.read(split.getStart() - headerLen, buf, 0, buf.length); // after long pos = Math.max(0, split.getStart() - headerLen); in.read(pos, buf, 0, buf.length);
Defensive patterns
Strategy: validation
Validate before calling
long safePos = Math.max(0, pos);
if (safePos != pos) {
LOG.warn("clamped negative read position {} -> {}", pos, safePos);
}
in.read(safePos, buf, off, len); Try / catch
try {
in.read(pos, buf, off, len);
} catch (EOFException e) {
if ("position is negative".equals(e.getMessage())) {
in.read(0, buf, off, len); // clamp and retry
} else {
throw e;
}
} Prevention
- Clamp all computed offsets with Math.max(0, ...) before positioned reads.
- Review seek/skip arithmetic for underflow when subtracting lookahead amounts.
- Validate user- or metadata-supplied offsets at input boundaries.
When it happens
Trigger: Calling in.read(negativePos, ...) directly, or via refill()/read(ByteBuffer) when the tracked position variable became negative through a bad seek/skip (e.g. seek to negative clamped by another path, or position decremented past zero).
Common situations: Custom readers computing pos = current - backoff with underflow; reading ahead of a seek(0)-then-read pattern where position arithmetic goes negative; wrappers that pass user-supplied offsets unvalidated.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- arguments: " + off + " " + len
- Invalid start or len parameter
- stream was closed
- Path already exists: " + f
- File already exists: " + f
AI-assisted analysis of juicedata/juicefs@c9a67b23e8 (2026-09-06).
Data as JSON: /api/errors/09c5999d4cbc6354.
Report an issue: GitHub.