coleam00/Archon · warning

node_loop_interactive_deprecated

node_loop_interactive_deprecated

Error message

Node '${id}': node-level loop 'interactive:' is deprecated. A future release re-expresses the interactive loop as a gate + loop_group composition (#2707 step 3). Continue using it for now.

What it means

Node-level `interactive: true` on a loop or loop_group (the interactive loop where iteration output is reviewed by a human) is deprecated. The planned target model re-expresses the interactive loop as a gate + loop_group composition (#2707 step 3). The loader warns but the field keeps working for now — the message explicitly says to continue using it.

Source

Thrown at packages/workflows/src/loader.ts:472

          `Node '${id}': 'approval.on_reject' is deprecated. Declare 'approval.decisions' ` +
          `and wire a rework node with "when: \\"$${id}.output.decision == 'reject'\\"" ` +
          'instead (loop it with loop_group if it should iterate). This gate keeps running ' +
          'via the legacy mechanism until migrated.';
        warnings.push(message);
        getLog().warn({ id, warning: message }, 'node_on_reject_deprecated');
      }
    }
  }
  const interactiveLoop =
    (isLoopNode(node) && node.loop.interactive === true) ||
    (isLoopGroupNode(node) && node.loop_group.interactive === true);
  if (interactiveLoop) {
    const message =
      `Node '${id}': node-level loop 'interactive:' is deprecated. A future release ` +
      're-expresses the interactive loop as a gate + loop_group composition (#2707 step 3). ' +
      'Continue using it for now.';
    warnings.push(message);
    getLog().warn({ id, warning: message }, 'node_loop_interactive_deprecated');
  }

  // The prose `until:` completion channel is deprecated for EVERY loop/loop_group,
  // not only interactive ones (#2707 step 3, "What gets deleted"): its one stated
  // reason to exist — "the iteration output is a message a human reads at an
  // interactive gate" (#2563) — evaporates once that human interaction is a gate
  // node with structured decision output rather than a prose sentinel. `until_bash`
  // and (loop: only) `until_field` are the declared, structured replacements. This
  // keeps running exactly as before; only the guidance is new.
  if (isLoopNode(node) && node.loop.until !== undefined) {
    const message =
      `Node '${id}': the prose 'loop.until' completion signal is deprecated. Declare ` +
      "'loop.until_bash' (deterministic check) or 'loop.until_field' (a declared boolean " +
      'in output_format) instead (#2707 step 3). While supported, emit legacy signals as ' +
      "'<promise>SIGNAL</promise>' or a final standalone signal line.";
    warnings.push(message);
    getLog().warn({ id, warning: message }, 'node_loop_until_deprecated');
  } else if (isLoopGroupNode(node) && node.loop_group.until !== undefined) {

View on GitHub (pinned to 0773b97458)

Solutions

  1. Short-term: continue using it (the warning says so), but track the affected workflows.
  2. Plan the migration: re-express the interactive loop as an approval/decision gate plus loop_group — gate the iteration output to a human and loop the body until approval.
  3. Use deterministic completion checks (`until_bash`/`until_field`) during the rewrite.
  4. Migrate before #2707 step 3 ships and the composition change alters or removes the field.

Example fix

# before
loop:
  interactive: true
  prompt: "iterate"
# after: gate + loop_group composition
loop_group:
  body: [iterate]
  gate: human_review   # approval node reading $iterate.output
  until_bash: "test \"$human_review.output.decision\" = 'approve'"
Defensive patterns

Strategy: validation

Validate before calling

// Detect deprecated interactive loops so they can be scheduled for migration:
const interactive = workflow.nodes.filter(
  (n) => (n.type === 'loop' && n.loop?.interactive === true) ||
         (n.type === 'loop_group' && n.loop_group?.interactive === true)
);
if (interactive.length) console.warn('Migrate interactive loops to gate + loop_group:', interactive.map((n) => n.id));

Type guard

function isInteractiveLoopNode(node: { type: string; loop?: { interactive?: boolean }; loop_group?: { interactive?: boolean } }): boolean {
  return node.loop?.interactive === true || node.loop_group?.interactive === true;
}

Prevention

When it happens

Trigger: collectGateAndLoopDeprecationWarnings (via parseDagNode) on a workflow where a loop node has `loop.interactive: true` or a loop_group node has `loop_group.interactive: true` (loader.ts:472); fires on every parse.

Common situations: Interactive loops authored before the gate/loop_group composition model; workflows migrated from prose human-in-the-loop patterns; templates copied from older examples.

Related errors


AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01). Data as JSON: /api/errors/2ab1ea4c595b4a05. Report an issue: GitHub.