{"record":{"id":"e1894f460df9a342","repo":"prestodb/presto","slug":"negative-seek-offset","errorCode":null,"errorMessage":"Negative seek offset","messagePattern":"Negative seek offset","errorType":"exception","errorClass":"EOFException","httpStatus":null,"severity":"error","filePath":"presto-hive/src/main/java/com/facebook/presto/hive/s3/PrestoS3FileSystem.java","lineNumber":988,"sourceCode":"            this.maxAttempts = maxAttempts;\n            this.maxBackoffTime = requireNonNull(maxBackoffTime, \"maxBackoffTime is null\");\n            this.maxRetryTime = requireNonNull(maxRetryTime, \"maxRetryTime is null\");\n        }\n\n        @Override\n        public void close()\n        {\n            closed.set(true);\n            closeStream();\n        }\n\n        @Override\n        public int read(long position, byte[] buffer, int offset, int length)\n                throws IOException\n        {\n            checkClosed();\n            if (position < 0) {\n                throw new EOFException(NEGATIVE_SEEK);\n            }\n            checkPositionIndexes(offset, offset + length, buffer.length);\n            if (length == 0) {\n                return 0;\n            }\n\n            try {\n                return retry()\n                        .maxAttempts(maxAttempts)\n                        .exponentialBackoff(BACKOFF_MIN_SLEEP, maxBackoffTime, maxRetryTime, 2.0)\n                        .stopOn(InterruptedException.class, UnrecoverableS3OperationException.class, EOFException.class, FileNotFoundException.class, AbortedException.class)\n                        .onRetry(STATS::newGetObjectRetry)\n                        .run(\"getS3Object\", () -> {\n                            InputStream stream;\n                            try {\n                                GetObjectRequest request = new GetObjectRequest(host, keyFromPath(path))\n                                        .withRange(position, (position + length) - 1);\n                                stream = s3.getObject(request).getObjectContent();","sourceCodeStart":970,"sourceCodeEnd":1006,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-hive/src/main/java/com/facebook/presto/hive/s3/PrestoS3FileSystem.java#L970-L1006","documentation":"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.","triggerScenarios":"Calling FSDataInputStream.read(position, buffer, offset, length) with position < 0, typically from a corrupted split/offset computation or an uninitialized long used as position.","commonSituations":"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.","solutions":["Fix the caller's offset computation; log and clamp position to >= 0 upstream.","Verify file lengths used to compute back-positions (e.g. length - footerSize) are correct.","Guard reads: if (position < 0) throw IllegalArgumentException with context instead of proceeding.","Check for integer overflow when computing positions from int arithmetic; use long."],"exampleFix":"// before\nlong pos = fileLength - footerSize; // fileLength uninitialized -> -footerSize < 0\nin.read(pos, buffer, 0, len);\n// after\nlong pos = Math.max(0, fileLength - footerSize);\nif (fileLength <= 0) throw new IllegalStateException(\"invalid length\");\nin.read(pos, buffer, 0, len);","handlingStrategy":"validation","validationCode":"long safePos = position;\nif (safePos < 0) {\n    throw new IllegalArgumentException(\"read position must be >= 0, got \" + safePos);\n}","typeGuard":"boolean isValidRead(long position, byte[] buffer, int offset, int length) {\n    return position >= 0 && offset >= 0 && length >= 0 && offset + length <= buffer.length;\n}","tryCatchPattern":"try {\n    n = in.read(position, buffer, offset, length);\n} catch (EOFException e) {\n    if (NEGATIVE_SEEK.equals(e.getMessage())) {\n        throw new IllegalArgumentException(\"negative position passed to positional read\", e);\n    }\n    throw e;\n}","preventionTips":["Validate split start/length math before issuing positional reads.","Use long arithmetic when computing back-positions to avoid int overflow.","Initialize all position variables; never pass possibly-negative values.","Clamp or reject negative positions at your reader's API boundary."],"tags":["s3","filesystem","read","negative-offset"],"backgroundTag":"negative-seek-offset","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}