apache/iceberg · error · UncheckedIOException

Failed to read StreamingOffset from json

Error message

Failed to read StreamingOffset from json

What it means

StreamingOffset.fromJson(InputStream) reads a JSON node from a stream before parsing it into a StreamingOffset. Any IOException while reading the stream is wrapped in UncheckedIOException with a generic 'Failed to read StreamingOffset from json' message and the original cause attached.

Source

Thrown at spark/v3.5/spark/src/main/java/org/apache/iceberg/spark/source/StreamingOffset.java:80

    Preconditions.checkNotNull(json, "Cannot parse StreamingOffset JSON: null");

    try {
      JsonNode node = JsonUtil.mapper().readValue(json, JsonNode.class);
      return fromJsonNode(node);
    } catch (IOException e) {
      throw new UncheckedIOException(
          String.format("Failed to parse StreamingOffset from JSON string %s", json), e);
    }
  }

  static StreamingOffset fromJson(InputStream inputStream) {
    Preconditions.checkNotNull(inputStream, "Cannot parse StreamingOffset from inputStream: null");

    JsonNode node;
    try {
      node = JsonUtil.mapper().readValue(inputStream, JsonNode.class);
    } catch (IOException e) {
      throw new UncheckedIOException("Failed to read StreamingOffset from json", e);
    }

    return fromJsonNode(node);
  }

  @Override
  public String json() {
    StringWriter writer = new StringWriter();
    try (JsonGenerator generator = JsonUtil.factory().createGenerator(writer)) {
      generator.writeStartObject();
      generator.writeNumberField(VERSION, CURR_VERSION);
      generator.writeNumberField(SNAPSHOT_ID, snapshotId);
      generator.writeNumberField(POSITION, position);
      generator.writeBooleanField(SCAN_ALL_FILES, scanAllFiles);
      generator.writeEndObject();
      generator.flush();

    } catch (IOException e) {

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Check the wrapped cause for the underlying I/O failure (permissions, missing file, object-store error) and fix that.
  2. Retry the read — transient cloud-storage failures often resolve; ensure fresh stream per attempt.
  3. Verify the checkpoint offsets file still exists and isn't concurrently deleted by cleanup.

Example fix

// before
StreamingOffset offset = StreamingOffset.fromJson(cachedStream); // stream already consumed

// after
try (InputStream in = io.newInputFile(path).newStream()) {
  StreamingOffset offset = StreamingOffset.fromJson(in);
}
Defensive patterns

Strategy: retry

Validate before calling

if (!offsetFile.exists()) {
  throw new IllegalStateException("Offset file missing: " + offsetFile);
}

Try / catch

try (InputStream in = file.newStream()) {
  return StreamingOffset.fromJson(in);
} catch (UncheckedIOException e) {
  // inspect e.getCause(); retry transient object-store failures with backoff
}

Prevention

When it happens

Trigger: The InputStream passed to fromJson is unreadable — closed stream, file deleted between listing and read, network/FileIO failure while streaming the checkpoint offset.

Common situations: Concurrent checkpoint cleanup deleting the offsets file mid-read; object-store transient errors (S3/GCS) when reading offset files; passing an already-consumed stream.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12). Data as JSON: /api/errors/04f5c5896a519402. Report an issue: GitHub.