FoundationAgents/OpenManus · warning · ToolError

No plan found with ID: {plan_id}

Error message

No plan found with ID: {plan_id}

What it means

Raised by _update_plan (app/tool/planning.py:168) when command='update' targets a plan_id not present in the in-memory self.plans dict. The store is process-local (class-level dict), so IDs created in a previous process run or a different worker do not exist here. Checked before any mutation.

Source

Thrown at app/tool/planning.py:168

            "step_notes": [""] * len(steps),
        }

        self.plans[plan_id] = plan
        self._current_plan_id = plan_id  # Set as active plan

        return ToolResult(
            output=f"Plan created successfully with ID: {plan_id}\n\n{self._format_plan(plan)}"
        )

    def _update_plan(
        self, plan_id: Optional[str], title: Optional[str], steps: Optional[List[str]]
    ) -> ToolResult:
        """Update an existing plan with new title or steps."""
        if not plan_id:
            raise ToolError("Parameter `plan_id` is required for command: update")

        if plan_id not in self.plans:
            raise ToolError(f"No plan found with ID: {plan_id}")

        plan = self.plans[plan_id]

        if title:
            plan["title"] = title

        if steps:
            if not isinstance(steps, list) or not all(
                isinstance(step, str) for step in steps
            ):
                raise ToolError(
                    "Parameter `steps` must be a list of strings for command: update"
                )

            # Preserve existing step statuses for unchanged steps
            old_steps = plan["steps"]
            old_statuses = plan["step_statuses"]
            old_notes = plan["step_notes"]

View on GitHub (pinned to 52a13f2a57)

Solutions

  1. Run command='list' first and use an exact existing plan_id.
  2. If the plan is genuinely gone (restart/delete), recreate it with command='create' (rebuilding step statuses to not_started).
  3. If persistence matters, serialize plans outside the tool and replay creates on startup — the tool has no built-in storage.
  4. Normalize IDs at the caller (strip/consistent casing) to avoid mismatch collisions.

Example fix

// before
await planning.execute(command='update', plan_id='release-2', title='T')  # typo, never created

// after
plans = await planning.execute(command='list')
# pick exact id from output, then:
await planning.execute(command='update', plan_id='release-1', title='T')
Defensive patterns

Strategy: validation

Validate before calling

ids = await list_plan_ids(planning)  # via command='list'
if plan_id not in ids:
    raise KeyError(f'plan {plan_id!r} not found; existing: {sorted(ids)}')
await planning.execute(command='update', plan_id=plan_id, title=title)

Try / catch

try:
    await planning.execute(command='update', plan_id=pid, title=t)
except ToolError as e:
    if 'No plan found' in str(e):
        await planning.execute(command='create', plan_id=pid, title=t, steps=fallback_steps)
    else:
        raise

Prevention

When it happens

Trigger: Calling update with a typo'd or stale plan_id; updating after the plan was deleted (command='delete'); updating in a new process/session that never created the plan (no persistence between restarts).

Common situations: Agent sessions resumed after a process restart expecting plans to persist; horizontal scaling where each worker has its own class-level dict; ID casing/whitespace mismatches ('Plan1' vs 'plan1').

Related errors


AI-assisted analysis of FoundationAgents/OpenManus@52a13f2a57 (2026-08-15). Data as JSON: /api/errors/4cc8b0f1e8840bc4. Report an issue: GitHub.