apache/iceberg · error · RemotePlanTimeoutException

Remote scan planning for planId

Error message

Remote scan planning for planId: %s did not complete within configured limits (timeout=%d ms, maxRetries=%d)

What it means

Thrown as RemotePlanTimeoutException when the submitted remote scan plan never reached a terminal COMPLETED/FAILED/CANCELLED state within the configured polling limits (timeout and max retries). The client stops polling and reports the planId for follow-up.

Solutions

  1. Increase client wait properties (scan planning timeout ms and max retries) so polling covers server planning duration
  2. Reduce scan scope (partition filters) so server planning finishes faster
  3. Scale/optimize the server's planning service
  4. Use the reported planId to check server state; fetch the plan result out-of-band if the API allows

Example fix

// before
catalog.properties: rest.client.timeout=30000
// after
conf.put("rest.scan.plan.timeout-ms", "300000");
conf.put("rest.scan.plan.max-retries", "20");
Defensive patterns

Strategy: retry

Validate before calling

// ensure client wait budget exceeds expected planning time
long timeoutMs = Long.parseLong(conf.getOrDefault("rest.scan.plan.timeout-ms", "30000"));
int maxRetries = Integer.parseInt(conf.getOrDefault("rest.scan.plan.max-retries", "10"));

Try / catch

try { scan.planFiles(); } catch (RemotePlanTimeoutException e) {
  // e carries planId; optionally re-fetch or re-plan with bigger budget
}

Prevention

When it happens

Trigger: fetchPlanningResult exhausts its Tasks retry loop (maxRetries attempts each waiting up to timeout bounds) while the server keeps returning planStatus SUBMITTED.

Common situations: Very large scans where server planning exceeds client wait time; slow/overloaded REST planning service; client timeout properties set too low (e.g. rest.scan.plan.timeout-ms, max-retries).

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


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

Appendix: source

Thrown at core/src/main/java/org/apache/iceberg/rest/RESTTableScan.java:306

                  case SUBMITTED:
                    throw new NotCompleteException();
                  case FAILED:
                    throw new IllegalStateException(failureMessage(id, response.errorResponse()));
                  case CANCELLED:
                    throw new IllegalStateException(
                        String.format(
                            Locale.ROOT, "Remote scan planning cancelled for planId: %s", id));
                  default:
                    throw new IllegalStateException(
                        String.format(
                            Locale.ROOT,
                            "Invalid planStatus: %s for planId: %s",
                            response.planStatus(),
                            id));
                }
              });
    } catch (NotCompleteException e) {
      throw new RemotePlanTimeoutException(
          String.format(
              Locale.ROOT,
              "Remote scan planning for planId: %s did not complete within configured limits"
                  + " (timeout=%d ms, maxRetries=%d)",
              planId,
              maxWaitTimeMs,
              MAX_RETRIES),
          e);
    }

    FetchPlanningResultResponse response = result.get();

    this.scanFileIO =
        !response.credentials().isEmpty() ? scanFileIO(response.credentials()) : table().io();

    return scanTasksIterable(response.planTasks(), response.fileScanTasks());
  }

View on GitHub (pinned to 86d9c8fc54)