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

  1. Verify the operator has invoke permission on the resolved target agent (check the agent's visibility/invocation policy in the workspace).
  2. 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.
  3. Ask the agent owner or a workspace admin to grant the operator access, or reassign the issue to an agent the operator can invoke.
  4. 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

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


AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15). Data as JSON: /api/errors/9800e2e14485c2ac. Report an issue: GitHub.