ruvnet/ruflo · error
agent_execute failed
Error message
agent_execute failed
What it means
In a workflow 'task' step, executeAgentTask() (from agent-execute-core) returned { success: false } and this throw fires. 'agent_execute failed' is only the FALLBACK text used when result.error is empty — normally the real cause is propagated (e.g. 'Agent not found', 'Agent has been terminated', 'Anthropic API error 401: ...', 'Ollama API error ...', provider timeouts). Seeing the generic string means the failure path produced no message, so you must reproduce the agent call directly to learn why.
Solutions
- Verify the agent exists and is not terminated: call agent_list / agent_status with the same agentId the step uses.
- Reproduce outside the workflow: call agent_execute with the same agentId and prompt — it returns the detailed error string.
- Check provider configuration (API keys env vars, Ollama reachable, providerLabel endpoints) for the agent's configured model/provider.
- If the direct call also yields an empty error, capture it as a bug — success:false with no message is a lost-error defect in the execute path.
Example fix
// before
{ type: 'task', config: { agentId: 'coder-42', prompt: '...' } } // coder-42 from an old session
// workflow run -> step failed: 'agent_execute failed'
// after
await mcp.call('agent_spawn', { agentType: 'coder', agentId: 'coder-42' }); // ensure it exists
await mcp.call('agent_execute', { agentId: 'coder-42', prompt: 'ping' }); // verify, see real error if any
// then run the workflow Defensive patterns
Strategy: validation
Validate before calling
// Before workflow_run, confirm every referenced agent exists and is alive:
async function assertAgentsReady(agentIds: string[], mcp: McpClient): Promise<void> {
const { agents } = await mcp.call('agent_list', {});
const alive = new Map(agents.map((a: any) => [a.agentId, a.status]));
for (const id of agentIds) {
const status = alive.get(id);
if (!status) throw new Error(`agent ${id} not found — spawn it before the run`);
if (status === 'terminated') throw new Error(`agent ${id} is terminated — respawn before the run`);
}
} Type guard
interface AgentTaskResult { success: boolean; error?: string; output?: string }
function isFailedAgentResult(r: AgentTaskResult): r is AgentTaskResult & { success: false } {
return r.success === false;
} Try / catch
try {
return await callTool('workflow_run', { workflowId });
} catch (e) {
if ((e as Error).message === 'agent_execute failed') {
// Generic fallback text: real cause was empty — reproduce directly for the detailed error
const probe = await callTool('agent_execute', { agentId, prompt: 'ping' });
return stepError(`agent_execute failed (no message); direct probe says: ${probe.error ?? 'ok now — transient provider issue'}`);
}
throw e;
} Prevention
- Pre-check agent existence/status with agent_list before starting a workflow that references them.
- Keep provider config (API keys, Ollama URL) verified — provider errors propagate as result.error, so a healthy provider avoids the step failing at all.
- When a step fails with the generic message, always run the same agent via agent_execute to recover the real error string.
When it happens
Trigger: A task step whose agentId refers to a deleted or never-spawned agent; an agent whose status is 'terminated'; provider errors (bad/missing API key, 4xx/5xx from Anthropic/Ollama/custom provider); a provider failure mode that returns success:false without an error string, making the workflow surface the fallback message.
Common situations: Workflow templates referencing agent ids from a previous session (agent store is gone); API key rotated or expired between workflow runs; Ollama not running locally; agents terminated by a lifecycle cleanup while the workflow was still executing.
Related errors
- Execution failed after all attempts
- task step requires config.agentId or…
- Agent at maximum concurrent task capacity
- Agent has active tasks. Use force=true to terminate anyway.
- Agent ' ' not found
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/b8725c91c027ecd8.
Report an issue: GitHub.
Appendix: source
Thrown at v3/@claude-flow/cli/src/mcp-tools/workflow-tools.ts:365
let stepEntry: typeof stepResults[number] = { stepId: step.stepId, type: step.type, status: 'running' };
try {
if (step.type === 'task') {
const cfg = step.config as Record<string, unknown>;
const agentId = (cfg.agentId as string) || (workflow.variables.defaultAgentId as string);
const promptTpl = (cfg.prompt as string) || step.name;
if (!agentId) throw new Error(`task step ${step.stepId} requires config.agentId or workflow.variables.defaultAgentId`);
const prompt = interp(promptTpl);
const result = await executeAgentTask({
agentId,
prompt,
systemPrompt: cfg.systemPrompt ? interp(String(cfg.systemPrompt)) : undefined,
maxTokens: cfg.maxTokens as number | undefined,
temperature: cfg.temperature as number | undefined,
timeoutMs: cfg.timeoutMs as number | undefined,
});
if (!result.success) throw new Error(result.error || 'agent_execute failed');
step.result = result;
workflow.variables[`${step.stepId}.output`] = result.output;
workflow.variables.lastStepOutput = result.output;
stepEntry = { stepId: step.stepId, type: 'task', status: 'completed', durationMs: result.durationMs, output: result.output };
} else if (step.type === 'wait') {
const cfg = step.config as Record<string, unknown>;
const ms = Math.min(Math.max(0, (cfg.ms as number) || 0), 60000);
await new Promise(r => setTimeout(r, ms));
step.result = { waitedMs: ms };
stepEntry = { stepId: step.stepId, type: 'wait', status: 'completed', durationMs: ms };
} else if (step.type === 'condition') {
// Simple condition: config.when is a JS expression evaluated against workflow.variables.
// For safety, we only support `var === 'value'` or `var === number`.
const cfg = step.config as Record<string, unknown>;
const expr = String(cfg.when || 'true').trim();
const m = expr.match(/^([a-zA-Z_][\w]*)\s*===?\s*(['\"])?([^'\"]*)\2?$/);
let truthy = false;
if (m) {View on GitHub (pinned to fa13ee4ad6)