apache/iceberg · error · UncheckedIOException

Failed to parse StreamingOffset from JSON string %s

Error message

Failed to parse StreamingOffset from JSON string %s

What it means

StreamingOffset.fromJson throws UncheckedIOException wrapping the message when the offset's JSON string cannot be parsed into a JsonNode (malformed JSON, I/O error from Jackson). It converts the checked IOException into an unchecked one so it can surface from Spark checkpoint deserialization.

Source

Thrown at spark/v4.1/spark/src/main/java/org/apache/iceberg/spark/source/StreamingOffset.java:68

   * @param snapshotId The current processed snapshot id.
   * @param position The position of last scanned file in snapshot.
   * @param scanAllFiles whether to scan all files in a snapshot; for example, to read all data when
   *     starting a stream.
   */
  StreamingOffset(long snapshotId, long position, boolean scanAllFiles) {
    this.snapshotId = snapshotId;
    this.position = position;
    this.scanAllFiles = scanAllFiles;
  }

  static StreamingOffset fromJson(String json) {
    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

View on GitHub (pinned to 86d9c8fc54)

Solutions

  1. Inspect and repair the checkpoint location's offset/state JSON files
  2. Delete the corrupted checkpoint and restart the streaming query (data will be reprocessed per source semantics)
  3. Verify all executors/drivers use the same Iceberg version
  4. If calling fromJson manually, validate the string is well-formed JSON before passing it

Example fix

// before
StreamingOffset offset = StreamingOffset.fromJson(userProvidedString); // may throw
// after
try {
  StreamingOffset offset = StreamingOffset.fromJson(json);
} catch (UncheckedIOException e) {
  // fall back to re-initializing offsets from the table
}
Defensive patterns

Strategy: try-catch

Validate before calling

try { JsonUtil.mapper().readTree(offsetJson); } catch (Exception e) { /* reject/re-initialize before passing to fromJson */ }

Try / catch

try {
  StreamingOffset offset = StreamingOffset.fromJson(json);
} catch (UncheckedIOException e) {
  // treat as corrupt checkpoint: re-initialize offsets from table state
}

Prevention

When it happens

Trigger: Spark structured streaming restores a StreamingOffset from checkpoint state where the stored JSON string is corrupt, truncated, or produced by an incompatible schema/version; calling fromJson directly with a non-JSON string.

Common situations: Corrupted or hand-edited checkpoint files; offset JSON written by a different Iceberg version that fails to parse; disk issues truncating checkpoint files during recovery after failure.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


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