Skip to content

Troubleshooting

This guide helps recover from common issues when working with MCP Moira workflows.

Context Recovery After Session Archive

When a conversation is archived or compacted, the agent loses:

  • Current execution ID (processId)
  • Workflow step context
  • Progress information

The workflow state persists on the MCP server - only the agent’s memory is lost.

Recovery Steps

  1. Find active executions:
session({ action: "executions" })

Returns list of executions with status, workflow ID, and notes:

[
{
"executionId": "abc-123",
"workflowId": "development-flow",
"status": "waiting",
"note": "Feature: auth system",
"currentNodeId": "implement-step"
}
]
  1. Get current step without advancing:
session({ action: "current_step", executionId: "abc-123" })

Returns the current directive and context:

{
"attemptId": "attempt-current",
"directive": "Implement the feature...",
"completionCondition": "Feature working and tested",
"inputSchema": { ... }
}
  1. Continue workflow:
step({ processId: "abc-123", attemptId: "attempt-current", input: { ... } })

Process ID Preservation

To help future recovery, save the process ID in your workspace:

Terminal window
# Create process-id.txt in feature directory
echo "abc-123" > ./feature-name/process-id.txt

Include in session archives:

  • Feature name
  • Process ID
  • Current step description

session - executions

Lists all active workflow executions for current user.

Call: session({ action: "executions" })

Filters:

  • status: Array of statuses - ["waiting", "running", "completed", "failed"]
  • workflowId: Filter by specific workflow
  • search: Search in execution notes

Example with filters:

session({
action: "executions",
status: ["waiting", "running"],
search: "auth"
})

session - current_step

Retrieves current step directive without advancing the workflow.

Call: session({ action: "current_step", executionId: "..." })

Parameters:

  • executionId (required): Execution ID to check

Returns:

  • attemptId: Identity required to submit this exact current presentation
  • directive: What to do
  • completionCondition: Success criteria
  • inputSchema: Response structure

session - execution_context

Gets full execution state including context variables.

Call: session({ action: "execution_context", executionId: "..." })

Parameters:

  • executionId (required): Execution ID to inspect

Returns:

  • executionId: Execution UUID
  • workflowId: Workflow being executed
  • status: Execution status (running, waiting, completed, failed)
  • currentNodeId: Current node ID
  • waitingForInputNodeId: Node waiting for input (if any)
  • note: Execution note
  • context.variables: Context variables
  • context.nodeStates: Node execution states
  • createdAt, updatedAt, completedAt: Timestamps
  • error: Error message (if failed)

Common Issues

“Process not found or expired”

Cause: Invalid or expired processId

Solution:

  1. Use session({ action: "executions" }) to find active executions
  2. Use the correct executionId from the list
  3. Process IDs are UUIDs like abc123-def456-...

“Execution is not waiting for input”

Cause: Trying to advance a completed or failed execution

Solution:

  1. Check execution status with session({ action: "execution_context", executionId: "..." })
  2. Status must be waiting to accept input
  3. If completed or failed, start a new execution

Validation Errors on step()

Cause: Input doesn’t match inputSchema

Solution:

  1. Check inputSchema from current step
  2. Verify field names match exactly (case sensitive)
  3. Verify data types match (string vs number)
  4. Include all required fields

ATTEMPT_PROCESSING

Cause: Another caller still has a live claim on this exact step mutation.

Solution: Retry with the same Process ID, Step attempt ID, and input. Do not replace the attempt or alter the input.

ATTEMPT_STALE

Cause: The attempt no longer matches the current execution presentation and was rejected before handler work.

Solution: Automatically call session({ action: "current_step", executionId: "..." }), then retry the intended submission once with the returned Step attempt ID. Do not reuse the stale ID.

ATTEMPT_CONFLICT

Cause: The attempt is already bound to a different input and the new submission was rejected before handler work.

Solution: Automatically call session({ action: "current_step", executionId: "..." }), discard the conflicting attempt, and continue from the returned directive and input schema. Do not replay the rejected input against the current presentation.

ATTEMPT_INVALID_OR_EXPIRED for a step

Cause: The step attempt is unavailable and was rejected before handler work. This recovery applies only when the error explicitly directs the caller to current_step; an unavailable start attempt has no current step to recover.

Solution: Automatically call session({ action: "current_step", executionId: "..." }), discard the unavailable attempt, and continue from the returned directive and input schema.

ATTEMPT_OUTCOME_UNKNOWN

Cause: Moira could not prove whether a claimed mutation and its possible external effect completed.

Solution: Inspect the execution with session({ action: "current_step", executionId: "..." }) and the relevant external system. Do not automatically retry the mutation.

CURRENT_PRESENTATION_STALE

Cause: The persisted live attempt belongs to a different node, or to a continuation surface the current definition no longer has: something the paused node declares about what it does changed, or a registry entry for a global variable it declares as an input did. It cannot be safely rebound to the current execution. A change that does not reach that surface does not produce this state — a version or tag bump, an edit to another node, or a cosmetic change to the paused node itself all leave the run usable.

Solution: Do not retry the old attempt. Call session({ action: 'diagnose', executionId: '...' }), which names which facts of the paused step changed, whether its node still exists, and anything else standing between the run and its next step. Then repair the run with session({ action: 'recover', executionId: '...', nodeId: '<node to resume from>', variableValues: { ... } }), which re-presents it at the node you name with the values that step needs and returns a fresh Step attempt ID to continue from. Name a node a run can wait on — an agent-directive, teleport, materialize, lock or subgraph node; any other node is refused, because resuming there would run the workflow forward instead of repairing it. The run comes to rest on the node you name and never goes past it, but a lock node creates its lock and sends its approval code when the run arrives there, and a subgraph node enters its child — choose one of those as the target only when you want that. Recovery is also refused unless the run really cannot continue, and refused for a run that is already finished or cancelled, which stays that way; a refusal changes nothing.

Agent Forgets Workflow Context

Cause: Session was archived/compacted

Solution:

  1. Check for process-id.txt in workspace
  2. Use session({ action: "current_step" }) to get context
  3. Remind agent: “Continue workflow {processId}”

Seeing [[UNDEFINED_VARIABLE]] in a directive at runtime

Cause: A referenced variable was unresolved when the directive was rendered. Three causes:

  1. The variable is not declared in variableRegistry.
  2. The variable is declared but has no default and was not yet written by an upstream node before the directive used it.
  3. A bare {{...}} was placed into data the agent returned via step(), and that data was later interpolated into a directive (template-in-data). Returned data values are literal — they are not re-scanned as templates.

The engine logs a warning naming the residual placeholder and the executionId.

Solution:

  1. Declare the variable in variableRegistry with a default.
  2. Ensure an upstream node writes the variable (via globalInputs) before its first use.
  3. Never echo {{...}} into data you return from step() — keep templates only in static node fields.

Recovery Scenarios

Scenario: Resume After Interruption

User: Continue working on the auth feature
Agent:
1. session({ action: "executions", search: "auth" })
→ Found: executionId: "abc-123", status: "waiting"
2. session({ action: "current_step", executionId: "abc-123" })
→ attemptId: "attempt-current", directive: "Implement login endpoint"
3. [Does the work]
4. step({ processId: "abc-123", attemptId: "attempt-current", input: { result: "done" } })

Scenario: Find Lost Process ID

User: What workflows am I running?
Agent:
1. session({ action: "executions" })
→ Lists all active executions with notes
2. session({ action: "execution_context", executionId: "abc-123" })
→ Shows full context including variables

Scenario: Check Why Workflow Stuck

Agent:
1. session({ action: "execution_context", executionId: "abc-123" })
→ status: "waiting", currentNodeId: "validation-step"
2. session({ action: "current_step", executionId: "abc-123" })
→ Shows what the workflow is waiting for