apache/iceberg · error · IOException
Invalid position: ${newPos}
Error message
Invalid position: ${newPos} What it means
AesGcmInputStream.seek() rejects positions before the start of the plaintext stream. Calling seek with a negative newPos throws IOException("Invalid position: ..."). This is a plain argument validation protecting the underlying decrypting stream state.
Source
Thrown at core/src/main/java/org/apache/iceberg/encryption/AesGcmInputStream.java:151
remainingBytesToRead -= bytesToCopy;
resultBufferOffset += bytesToCopy;
this.plainStreamPosition += bytesToCopy;
} else if (available() > 0) {
decryptBlock(blockIndex(plainStreamPosition));
} else {
break;
}
}
// return -1 for EOF
return totalBytesRead > 0 ? totalBytesRead : -1;
}
@Override
public void seek(long newPos) throws IOException {
if (newPos < 0) {
throw new IOException("Invalid position: " + newPos);
} else if (newPos > plainStreamSize) {
throw new EOFException(
"Invalid position: " + newPos + " > stream length, " + plainStreamSize);
}
this.plainStreamPosition = newPos;
}
@Override
public long skip(long n) {
if (n <= 0) {
return 0;
}
long bytesLeftInStream = plainStreamSize - plainStreamPosition;
if (n > bytesLeftInStream) {
// skip the rest of the stream
this.plainStreamPosition = plainStreamSize;View on GitHub (pinned to 86d9c8fc54)
Solutions
- Fix the caller's offset computation so it never produces negative positions
- Validate/clamp positions before calling seek
- Check whether an upstream read returned -1 (EOF sentinel) that was then used as a seek offset
Example fix
// before
stream.seek(offset); // offset may be -1 from a failed read
// after
if (offset >= 0) { stream.seek(offset); } else { throw new EOFException("No data read"); } Defensive patterns
Strategy: validation
Validate before calling
if (newPos < 0) { throw new IllegalArgumentException("Position must be >= 0, got " + newPos); } Type guard
boolean isValidSeek(long pos) { return pos >= 0; } Try / catch
try { stream.seek(pos); } catch (IOException e) { throw new IllegalStateException("Seek failed: check offset computation", e); } Prevention
- Never use read() return value -1 as a seek offset
- Check offset arithmetic for long underflow/overflow
- Validate positions against stream size before seeking
When it happens
Trigger: Calling seek(negativeLong) on an AesGcmInputStream, typically from a reader computing offsets with signed/overflow arithmetic bugs or uninitialized offsets.
Common situations: Parquet/ORC readers restoring positions from uninitialized or corrupted page offsets; long underflow in offset arithmetic when reading encrypted files.
Related errors
- Invalid position: ${newPos} > stream length, ${plainStreamSi
- File length is null
- File length unknown, creating an AesGcmInputFile is not safe
- Failed to create file: %s
- Failed to delete: %s
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/81f3e7064fd2ca91.
Report an issue: GitHub.