multica-ai/multica · error · ErrRerunInvokeNotAllowed
rerun: operator not allowed to invoke target agent
Error message
rerun: operator not allowed to invoke target agent
What it means
Returned by RerunIssue when the current operator is not permitted to invoke the resolved target agent. The check (canInvoke) runs after the rerun target is resolved but before any prior task is cancelled or a new one created, so a blocked rerun mutates nothing. The HTTP handler maps this sentinel to a structured 403. It exists to stop callers who can see an issue from using rerun as a back door into a private agent assigned to that issue.
Source
Thrown at server/internal/service/task.go:4506
// runtime_offline, timeout, or an auth/quota/config error the user has since
// fixed — should not throw away the work already done. Only the agent SESSION
// is conditionally resumed, and that decision is made later by the daemon claim
// handler from the SOURCE task (via rerun_of_task_id), NOT baked into this row.
// enqueueRerunTask pins force_fresh_session=true so an old claim handler during
// a rolling deploy degrades to a clean start rather than resuming a different
// execution; the new claim handler ignores the flag for reruns and resumes the
// session only when the source failure did not poison the conversation (see
// service.ResumeUnsafeFailure) and the source ran on the same runtime. When the
// dir is objectively unreusable (GC'd, absent on the claiming runtime, or never
// recorded) the daemon falls back to a fresh workdir. Auto-retry of an orphaned
// mid-flight failure (HandleFailedTasks → MaybeRetryFailedTask →
// CreateRetryTask) takes its own path, so MUL-1128's mid-flight resume contract
// is preserved.
//
// ErrRerunInvokeNotAllowed signals that RerunIssue refused to rerun because the
// current operator may not invoke the resolved target agent. The handler maps it
// to a structured 403 (no task was cancelled or created).
var ErrRerunInvokeNotAllowed = errors.New("rerun: operator not allowed to invoke target agent")
// Only tasks belonging to the target agent on this issue are cancelled.
// Tasks owned by other agents on the same issue (e.g. a parallel
// @-mention agent) are left alone — rerun must not collateral-cancel
// them.
//
// canInvoke re-validates that the current operator may invoke the RESOLVED
// target agent, keyed on the historical agent for a task_id rerun and on the
// current assignee/leader otherwise (MUL-4525). It runs AFTER the target is
// resolved but BEFORE any prior task is cancelled or a new one is created, so a
// caller who can see the issue but cannot invoke its private agent cannot use
// rerun as a back door — and a blocked rerun mutates nothing. Pass nil only
// from trusted internal callers (tests, backfill) that have already gated.
func (s *TaskService) RerunIssue(ctx context.Context, issueID pgtype.UUID, sourceTaskID pgtype.UUID, triggerCommentID pgtype.UUID, actorUserID pgtype.UUID, canInvoke func(agent db.Agent) bool) (*db.AgentTaskQueue, error) {
issue, err := s.Queries.GetIssue(ctx, issueID)
if err != nil {
return nil, fmt.Errorf("load issue: %w", err)
}View on GitHub (pinned to 2c0912b6ec)
Solutions
- Verify the operator has invoke permission on the resolved target agent (check the agent's visibility/invocation policy in the workspace).
- If rerunning by task_id, confirm the task belongs to an agent the operator may invoke; otherwise rerun without task_id so the current assignee is used.
- Ask the agent owner or a workspace admin to grant the operator access, or reassign the issue to an agent the operator can invoke.
- If you own the agent, make sure it is not configured private when team reruns are expected.
Example fix
// before
resp, err := client.RerunIssue(ctx, issueID, WithTaskID(taskID))
// 403 rerun: operator not allowed to invoke target agent
// after
agent := resolveTargetAgent(ctx, taskID) // historical agent for task_id reruns
if !operatorCanInvoke(ctx, operator, agent.ID) {
return fmt.Errorf("no rerun permission on agent %s; ask owner for access", agent.ID)
}
resp, err := client.RerunIssue(ctx, issueID, WithTaskID(taskID)) Defensive patterns
Strategy: try-catch
Validate before calling
// Before rerunning, resolve the target agent and check invoke permission
agent := resolveRerunTarget(ctx, issueID, taskID) // historical agent for task_id rerun
if !canInvokeAgent(ctx, operator, agent.ID) {
return fmt.Errorf("operator lacks invoke permission on agent %s", agent.ID)
} Try / catch
if err := svc.RerunIssue(ctx, req); err != nil {
if errors.Is(err, service.ErrRerunInvokeNotAllowed) {
// 403: nothing was cancelled or created; surface agent identity + permission hint
return renderForbidden(err)
}
return internal(err)
} Prevention
- Grant the calling operator invoke access to the issue's assigned agent before exposing rerun buttons to them.
- When rerunning by task_id, remember the permission check keys on the historical agent, not the current assignee.
- Treat this 403 as non-retryable — it mutates nothing and will keep failing until permissions change.
When it happens
Trigger: POST to the rerun endpoint for an issue whose target agent (historical agent for a task_id rerun, or current assignee/leader otherwise, per MUL-4525) is private or otherwise not invokable by the calling operator. Also hit when rerunning by task_id that belongs to a different agent the operator cannot invoke.
Common situations: A teammate reruns an issue whose agent was assigned by another user and marked private; an automation token with issue-read but not agent-invoke scope calls rerun; rerunning a task_id that was executed by an agent since made private.
Related errors
- list agents: %w
- get agent: %w
- fetch agents: %w
- Invalid desktop runtime config JSON: ${err instanceof Error
- creation_studio.builder.start_failed
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/9800e2e14485c2ac.
Report an issue: GitHub.