{"record":{"id":"fd061d345343b47b","repo":"apache/iceberg","slug":"cannot-find-plan-with-id-s","errorCode":null,"errorMessage":"Cannot find plan with id %s","messagePattern":"Cannot find plan with id (.+?)","errorType":"exception","errorClass":"NoSuchPlanIdException","httpStatus":404,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/rest/InMemoryPlanningState.java","lineNumber":84,"sourceCode":"  void addPlanTask(String planTaskKey, List<FileScanTask> tasks) {\n    planTaskToFileScanTasks.put(planTaskKey, tasks);\n  }\n\n  void addNextPlanTask(String currentTask, String nextTask) {\n    planTaskToNext.put(currentTask, nextTask);\n  }\n\n  void addAsyncPlan(String plan) {\n    PlanStatus existingStatus = asyncPlanningStates.get(plan);\n    Preconditions.checkArgument(\n        existingStatus == null, \"Plan %s already exists with status %s\", plan, existingStatus);\n    asyncPlanningStates.put(plan, PlanStatus.SUBMITTED);\n  }\n\n  PlanStatus asyncPlanStatus(String plan) {\n    PlanStatus existingStatus = asyncPlanningStates.get(plan);\n    if (existingStatus == null) {\n      throw new NoSuchPlanIdException(\"Cannot find plan with id %s\", plan);\n    }\n\n    return asyncPlanningStates.get(plan);\n  }\n\n  void markAsyncPlanAsComplete(String plan) {\n    PlanStatus existingStatus = asyncPlanningStates.get(plan);\n    Preconditions.checkArgument(existingStatus != null, \"Cannot find plan %s\", plan);\n    Preconditions.checkArgument(\n        existingStatus == PlanStatus.SUBMITTED,\n        \"Cannot mark plan %s as completed as it is %s\",\n        plan,\n        existingStatus);\n    asyncPlanningStates.put(plan, PlanStatus.COMPLETED);\n  }\n\n  void markAsyncPlanFailed(String plan) {\n    PlanStatus existingStatus = asyncPlanningStates.get(plan);","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/rest/InMemoryPlanningState.java#L66-L102","documentation":"InMemoryPlanningState (used by the in-memory REST test server) tracks asynchronously submitted scan plans by ID. asyncPlanStatus looks up the plan's status; if the ID is not in the map, NoSuchPlanIdException is thrown. This means the caller asked about a plan that was never submitted or has been forgotten by this state store.","triggerScenarios":"Polling plan status via the REST planning endpoint with an unknown/typo'd plan ID; querying a plan before submitting it; using a plan ID from a different server instance or after the in-memory state was recreated.","commonSituations":"Client retried a request against a restarted in-memory test server (IDs not persisted); race where a status poll fires before the SUBMITTED registration; stale plan IDs held across test setups.","solutions":["Submit the plan first (via the async plan endpoint) and use the returned plan ID","Verify the plan ID string matches the one returned by plan submission exactly","Re-submit the plan if the in-memory state server was restarted","Check client/server flow ordering: status polls must follow a successful submit"],"exampleFix":"// before\nString planId = someStaleId; // may not exist\n// after\nString planId = restClient.post(\"v1/plan\", planReq, PlanResponse.class).planId();\nPlanStatus status = planningState.asyncPlanStatus(planId);","handlingStrategy":"try-catch","validationCode":"if (planId == null || planningState == null) throw new IllegalStateException(\"Plan must be submitted before polling status\");","typeGuard":"boolean planExists(String planId, InMemoryPlanningState s) {\n  return planId != null && s != null && s.asyncPlanStatusOrNull(planId) != null; // if such accessor exists\n}","tryCatchPattern":"try {\n  status = planningState.asyncPlanStatus(planId);\n} catch (NoSuchPlanIdException e) {\n  status = PlanStatus.FAILED; // or re-submit the plan\n}","preventionTips":["Keep the plan ID returned by plan submission and use only that","Do not persist plan IDs across in-memory server restarts","Poll status only after a confirmed successful submit","Log the submitted plan ID for correlation"],"tags":["rest-catalog","planning","not-found"],"backgroundTag":"resource-not-found","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}