prestodb/presto · error · EOFException

Negative seek offset

Error message

Negative seek offset

What it means

PrestoS3InputStream.read(position, buffer, offset, length) throws EOFException with 'Negative seek offset' when a positional (pread-style) read is requested at a negative file position. Positional reads must address a valid offset within the object.

Source

Thrown at presto-hive/src/main/java/com/facebook/presto/hive/s3/PrestoS3FileSystem.java:988

            this.maxAttempts = maxAttempts;
            this.maxBackoffTime = requireNonNull(maxBackoffTime, "maxBackoffTime is null");
            this.maxRetryTime = requireNonNull(maxRetryTime, "maxRetryTime is null");
        }

        @Override
        public void close()
        {
            closed.set(true);
            closeStream();
        }

        @Override
        public int read(long position, byte[] buffer, int offset, int length)
                throws IOException
        {
            checkClosed();
            if (position < 0) {
                throw new EOFException(NEGATIVE_SEEK);
            }
            checkPositionIndexes(offset, offset + length, buffer.length);
            if (length == 0) {
                return 0;
            }

            try {
                return retry()
                        .maxAttempts(maxAttempts)
                        .exponentialBackoff(BACKOFF_MIN_SLEEP, maxBackoffTime, maxRetryTime, 2.0)
                        .stopOn(InterruptedException.class, UnrecoverableS3OperationException.class, EOFException.class, FileNotFoundException.class, AbortedException.class)
                        .onRetry(STATS::newGetObjectRetry)
                        .run("getS3Object", () -> {
                            InputStream stream;
                            try {
                                GetObjectRequest request = new GetObjectRequest(host, keyFromPath(path))
                                        .withRange(position, (position + length) - 1);
                                stream = s3.getObject(request).getObjectContent();

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Fix the caller's offset computation; log and clamp position to >= 0 upstream.
  2. Verify file lengths used to compute back-positions (e.g. length - footerSize) are correct.
  3. Guard reads: if (position < 0) throw IllegalArgumentException with context instead of proceeding.
  4. Check for integer overflow when computing positions from int arithmetic; use long.

Example fix

// before
long pos = fileLength - footerSize; // fileLength uninitialized -> -footerSize < 0
in.read(pos, buffer, 0, len);
// after
long pos = Math.max(0, fileLength - footerSize);
if (fileLength <= 0) throw new IllegalStateException("invalid length");
in.read(pos, buffer, 0, len);
Defensive patterns

Strategy: validation

Validate before calling

long safePos = position;
if (safePos < 0) {
    throw new IllegalArgumentException("read position must be >= 0, got " + safePos);
}

Type guard

boolean isValidRead(long position, byte[] buffer, int offset, int length) {
    return position >= 0 && offset >= 0 && length >= 0 && offset + length <= buffer.length;
}

Try / catch

try {
    n = in.read(position, buffer, offset, length);
} catch (EOFException e) {
    if (NEGATIVE_SEEK.equals(e.getMessage())) {
        throw new IllegalArgumentException("negative position passed to positional read", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling FSDataInputStream.read(position, buffer, offset, length) with position < 0, typically from a corrupted split/offset computation or an uninitialized long used as position.

Common situations: Hive/Spark split math bug (start offset underflow); reading footer/trailer by subtracting from a wrong file length; uninitialized offset variable; integer overflow wrapping negative.

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/e1894f460df9a342. Report an issue: GitHub.