paperclipai/paperclip · error · RunnerGoalActionError
agent_not_assigned
agent_not_assigned
Error message
agent_not_assigned: The selected agent is not assigned to this issue.
What it means
The runner goal action API (`act` in server/src/services/runner-goals.ts) validates that the agentId in the request is the current assignee of the issue. It throws RunnerGoalActionError with code `agent_not_assigned` when `binding.issue.assigneeAgentId !== request.agentId`. This enforces the single-assignee task model: only the assigned agent may manage session goals.
Source
Thrown at server/src/services/runner-goals.ts:360
goal,
workingNow: goal?.workingNow ?? false,
activeRunId: activeRun?.id ?? null,
pendingAction: projectedPendingAction,
revision: session?.goalRevision ?? 0,
observedAt: session?.goalObservedAt?.toISOString() ?? null,
};
}
async function act(
companyId: string,
issueId: string,
request: RunnerGoalActionRequest,
): Promise<RunnerGoalActionAccepted> {
const binding = await readBinding(companyId, issueId, request.agentId);
if (!binding) throw new RunnerGoalActionError("issue_not_found", "Issue not found.");
if (!binding.agent) throw new RunnerGoalActionError("agent_not_found", "Agent not found.");
if (binding.issue.assigneeAgentId !== request.agentId) {
throw new RunnerGoalActionError("agent_not_assigned", "The selected agent is not assigned to this issue.");
}
const fallbackCapability = capabilityForAgent(binding.agent);
const initialProjection = await projection(companyId, issueId, request.agentId);
if (!initialProjection) throw new RunnerGoalActionError("issue_not_found", "Issue not found.");
if (initialProjection.capability.availability !== "available") {
throw new RunnerGoalActionError(
initialProjection.capability.reasonCode ?? "session_goals_unsupported",
initialProjection.capability.reason ?? "Session goals are unsupported.",
);
}
const accepted = await db.transaction(async (tx) => {
await tx.insert(agentTaskSessions).values({
companyId,
agentId: request.agentId,
adapterType: binding.agent!.adapterType,
taskKey: issueId,
}).onConflictDoNothing();View on GitHub (pinned to 01ad858492)
Solutions
- Fetch the issue and check `assigneeAgentId` before calling, and use that agent's id in the request
- Re-read the issue (assignment may have changed) and retry with the current assignee
- If your agent should own the issue, reassign it first through the issue assignment API
- Check company scoping: ensure you are querying the right company/issue so the binding matches your agent
Example fix
// before
await runnerGoals.act(companyId, issueId, { agentId: someAgentId, action: 'pause', ... });
// after
const issue = await getIssue(companyId, issueId);
if (!issue || issue.assigneeAgentId !== someAgentId) return; // or use issue.assigneeAgentId
await runnerGoals.act(companyId, issueId, { agentId: issue.assigneeAgentId, action: 'pause', ... }); Defensive patterns
Strategy: validation
Validate before calling
const issue = await getIssue(companyId, issueId);
if (!issue || issue.assigneeAgentId !== agentId) {
throw new Error(`agent ${agentId} is not the assignee of issue ${issueId}`);
} Type guard
function isAssigned(issue, agentId) {
return issue != null && issue.assigneeAgentId === agentId;
} Try / catch
try {
await runnerGoals.act(companyId, issueId, req);
} catch (e) {
if (e instanceof RunnerGoalActionError && e.code === 'agent_not_assigned') {
// refresh assignment or reassign, then retry with issue.assigneeAgentId
} else throw e;
} Prevention
- Always read the issue's assigneeAgentId immediately before goal actions
- Pass issue.assigneeAgentId as the request agentId, never a cached value
- Re-fetch assignment after any reassignment event
- Scope automation to a single assigned agent per issue
When it happens
Trigger: Calling POST session-goal act (RunnerGoalActionRequest) with an agentId that exists in the binding but is not `issue.assigneeAgentId` — e.g. a non-assignee agent trying to pause/resume/clear/set goals on an issue assigned to a different agent.
Common situations: Board or tooling sends the wrong agent id; an issue was reassigned to another agent after the session was created; automated scripts iterate over agents and hit issues they don't own.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- evaluation_issue_required
- not_authorized
- agent_authorization_required
- Probe found no matching Anthropic Agent
- Existing Anthropic Agent model does not match the requested
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/1d28c665c6aee23b.
Report an issue: GitHub.