ruvnet/ruflo · error

No active task to checkpoint

Error message

No active task to checkpoint

What it means

Thrown by LongRunningWorker#saveCheckpoint (v3/@claude-flow/integration/src/long-running-worker.ts:407) when there is no currentLongTask/currentState — i.e. saveCheckpoint() was called while the worker is idle, not during task execution. Checkpoints snapshot in-flight state, so there is nothing to snapshot without an active task.

Source

Thrown at v3/@claude-flow/integration/src/long-running-worker.ts:407

          checkpointId: this.checkpoints[this.checkpoints.length - 1]?.id,
          progress: this.calculateProgress(),
        },
      };
    } finally {
      this.stopTimers();
      this.currentLongTask = null;
      this.abortController = null;
    }
  }

  /**
   * Save a checkpoint of the current execution state
   *
   * @returns Created checkpoint
   */
  async saveCheckpoint(): Promise<Checkpoint> {
    if (!this.currentLongTask || !this.currentState) {
      throw new Error('No active task to checkpoint');
    }

    this.checkpointSequence++;

    const checkpoint: Checkpoint = {
      id: `cp_${this.id}_${this.currentLongTask.id}_${this.checkpointSequence}`,
      taskId: this.currentLongTask.id,
      workerId: this.id,
      sequence: this.checkpointSequence,
      timestamp: Date.now(),
      state: { ...this.currentState },
      progress: this.calculateProgress(),
      metadata: {
        executionDuration: Date.now() - this.executionStartTime,
      },
    };

    // Save to storage

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Only checkpoint while a task runs — hook the worker's own lifecycle (progress/state-update events) instead of an external timer.
  2. Guard the call: if (!worker.hasActiveTask) skip (or expose/track currentLongTask via a status getter).
  3. If you need final state persisted, capture the task result at completion instead of checkpointing afterwards.
  4. For periodic safety, subscribe to state-update callbacks and checkpoint inside them, where a task is guaranteed active.

Example fix

// before
setInterval(() => worker.saveCheckpoint(), 30_000); // fires while idle -> throws

// after
worker.on('state-updated', async () => {
  if (worker.getCurrentTaskId()) await worker.saveCheckpoint();
});
Defensive patterns

Strategy: validation

Validate before calling

if (worker.getCurrentTaskId?.() ?? worker['currentLongTask']) {
  await worker.saveCheckpoint();
} else {
  logger.debug('skipping checkpoint: idle worker');
}

Type guard

function hasActiveTask(w: { getCurrentTaskId?: () => string | null }): boolean {
  return typeof w.getCurrentTaskId === 'function' && w.getCurrentTaskId() != null;
}

Try / catch

try {
  await worker.saveCheckpoint();
} catch (e) {
  if ((e as Error).message === 'No active task to checkpoint') return; // idle: nothing to do
  throw e;
}

Prevention

When it happens

Trigger: Calling saveCheckpoint() from an external timer/webhook between tasks; calling after the task finished (currentLongTask was reset to null in the completion path just above the throw site); a monitoring loop checkpointing on a schedule regardless of task state.

Common situations: Periodic checkpoint schedulers that do not know task boundaries; retry logic that checkpoints after a task already completed; race where the task's finally block cleared state before your checkpoint call landed.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/c005eb4c40d33e39. Report an issue: GitHub.