paperclipai/paperclip · error
${outcome.result.message} (fallback: runner_prp_command_${ou
Error message
${outcome.result.message} (fallback: runner_prp_command_${outcome.status}:${commandId}) What it means
When the awaited command reaches terminal status 'failed' or 'rejected', waitForCommand throws the outcome's own result.message when it is a string, otherwise a synthesized fallback 'runner_prp_command_failed:<id>' / 'runner_prp_command_rejected:<id>'. This error surfaces the runner's (or authority's) own failure reason for the command — the wait itself worked, the command did not succeed.
Source
Thrown at server/src/services/native-runtime/runner-prp-coordinator.ts:409
timer.unref();
}),
]);
} finally {
if (timer) clearTimeout(timer);
}
},
waitForCommand: async (commandId, timeoutMs = 30_000) => {
if (released) throw new Error("runner_prp_session_released");
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
const outcome = authority.commandOutcome(commandId);
if (!outcome) throw new Error(`runner_prp_command_missing:${commandId}`);
if (outcome.status === "completed") return outcome.result;
if (outcome.status === "failed" || outcome.status === "rejected") {
const message = outcome.result && typeof outcome.result.message === "string"
? outcome.result.message
: `runner_prp_command_${outcome.status}:${commandId}`;
throw new Error(message);
}
await new Promise<void>((resolve) => {
const timer = setTimeout(resolve, 10);
timer.unref();
});
}
throw new Error(`runner_prp_command_timeout:${commandId}`);
},
waitForGoalEvent: async (requestId, timeoutMs = 30_000) => {
if (released) throw new Error("runner_prp_session_released");
if (observedGoalRequests.has(requestId)) {
const error = observedGoalRequests.get(requestId);
if (error) throw new Error(error);
return;
}
let timer: NodeJS.Timeout | null = null;
let resolveGoalEvent!: () => void;
let rejectGoalEvent!: (error: Error) => void;View on GitHub (pinned to 01ad858492)
Solutions
- Read the error message — when it is not the fallback, it is the runner's own failure description; fix the root cause reported there (bad payload, missing permission, invalid command type).
- If you only see the fallback 'runner_prp_command_failed:<id>', add runner-side logging or inspect run/heartbeat events to recover the underlying failure reason.
- Ensure runner command handlers return results shaped as { message: string, ... } on failure so actionable messages propagate instead of the fallback.
- Distinguish rejected (policy) from failed (execution): if rejected, remove or adjust the command type/payload against governance rules before re-issuing.
Example fix
// before
await session.waitForCommand(commandId); // opaque fallback on failure
// after
try {
await session.waitForCommand(commandId);
} catch (e) {
if (/runner_prp_command_(failed|rejected):/.test(e.message)) {
logger.error({ commandId, reason: e.message }, 'command did not complete');
}
throw e;
} Defensive patterns
Strategy: try-catch
Type guard
const isCommandFailure = (e: unknown): e is Error => e instanceof Error && /^runner_prp_command_(failed|rejected):/.test(e.message);
Try / catch
try {
return await session.waitForCommand(commandId);
} catch (e) {
if (isCommandFailure(e)) {
// message carries the runner's failure/rejection reason (or fallback)
log.warn({ commandId, reason: e.message }, 'command not completed');
}
throw e;
} Prevention
- Make runner command handlers return { message: string } in every failure result so real causes surface instead of the fallback text.
- Validate command payloads against the runner's accepted schema before queueing.
- Check governance/policy rules before queueing command types that may be rejected.
- Log full error messages centrally to distinguish failed (execution) from rejected (policy) outcomes.
When it happens
Trigger: The runner reported the command as failed (execution error) or rejected (policy/permission refusal, e.g. a blocked question or disallowed tool call); or the runner completed the command with an error result lacking a string 'message' field, triggering the fallback message.
Common situations: Runner-side command handlers throwing; governance rules rejecting a queued command type; deserialization producing a result without a message field so only the generic fallback appears; agent-side denial of a requested action.
Related errors
- runner_prp_command_missing
- runner_prp_command_timeout
- Paperclip run authentication is unavailable
- paperclip_runner_approval_not_found
- paperclip_runner_codex_permission_mode_unqualified
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/0be3df07ccb60ea9.
Report an issue: GitHub.