{"record":{"id":"9800e2e14485c2ac","repo":"multica-ai/multica","slug":"rerun-operator-not-allowed-to-invoke-target-agent","errorCode":null,"errorMessage":"rerun: operator not allowed to invoke target agent","messagePattern":"rerun: operator not allowed to invoke target agent","errorType":"http","errorClass":"ErrRerunInvokeNotAllowed","httpStatus":403,"severity":"error","filePath":"server/internal/service/task.go","lineNumber":4506,"sourceCode":"// runtime_offline, timeout, or an auth/quota/config error the user has since\n// fixed — should not throw away the work already done. Only the agent SESSION\n// is conditionally resumed, and that decision is made later by the daemon claim\n// handler from the SOURCE task (via rerun_of_task_id), NOT baked into this row.\n// enqueueRerunTask pins force_fresh_session=true so an old claim handler during\n// a rolling deploy degrades to a clean start rather than resuming a different\n// execution; the new claim handler ignores the flag for reruns and resumes the\n// session only when the source failure did not poison the conversation (see\n// service.ResumeUnsafeFailure) and the source ran on the same runtime. When the\n// dir is objectively unreusable (GC'd, absent on the claiming runtime, or never\n// recorded) the daemon falls back to a fresh workdir. Auto-retry of an orphaned\n// mid-flight failure (HandleFailedTasks → MaybeRetryFailedTask →\n// CreateRetryTask) takes its own path, so MUL-1128's mid-flight resume contract\n// is preserved.\n//\n// ErrRerunInvokeNotAllowed signals that RerunIssue refused to rerun because the\n// current operator may not invoke the resolved target agent. The handler maps it\n// to a structured 403 (no task was cancelled or created).\nvar ErrRerunInvokeNotAllowed = errors.New(\"rerun: operator not allowed to invoke target agent\")\n\n// Only tasks belonging to the target agent on this issue are cancelled.\n// Tasks owned by other agents on the same issue (e.g. a parallel\n// @-mention agent) are left alone — rerun must not collateral-cancel\n// them.\n//\n// canInvoke re-validates that the current operator may invoke the RESOLVED\n// target agent, keyed on the historical agent for a task_id rerun and on the\n// current assignee/leader otherwise (MUL-4525). It runs AFTER the target is\n// resolved but BEFORE any prior task is cancelled or a new one is created, so a\n// caller who can see the issue but cannot invoke its private agent cannot use\n// rerun as a back door — and a blocked rerun mutates nothing. Pass nil only\n// from trusted internal callers (tests, backfill) that have already gated.\nfunc (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) {\n\tissue, err := s.Queries.GetIssue(ctx, issueID)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"load issue: %w\", err)\n\t}","sourceCodeStart":4488,"sourceCodeEnd":4524,"githubUrl":"https://github.com/multica-ai/multica/blob/2c0912b6ec764b373d44eeea1e80f0d9f11ab417/server/internal/service/task.go#L4488-L4524","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nresp, err := client.RerunIssue(ctx, issueID, WithTaskID(taskID))\n// 403 rerun: operator not allowed to invoke target agent\n\n// after\nagent := resolveTargetAgent(ctx, taskID) // historical agent for task_id reruns\nif !operatorCanInvoke(ctx, operator, agent.ID) {\n    return fmt.Errorf(\"no rerun permission on agent %s; ask owner for access\", agent.ID)\n}\nresp, err := client.RerunIssue(ctx, issueID, WithTaskID(taskID))","handlingStrategy":"try-catch","validationCode":"// Before rerunning, resolve the target agent and check invoke permission\nagent := resolveRerunTarget(ctx, issueID, taskID) // historical agent for task_id rerun\nif !canInvokeAgent(ctx, operator, agent.ID) {\n    return fmt.Errorf(\"operator lacks invoke permission on agent %s\", agent.ID)\n}","typeGuard":null,"tryCatchPattern":"if err := svc.RerunIssue(ctx, req); err != nil {\n    if errors.Is(err, service.ErrRerunInvokeNotAllowed) {\n        // 403: nothing was cancelled or created; surface agent identity + permission hint\n        return renderForbidden(err)\n    }\n    return internal(err)\n}","preventionTips":["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."],"tags":["authorization","rerun","api","forbidden","agents"],"backgroundTag":null,"analyzedSha":"2c0912b6ec764b373d44eeea1e80f0d9f11ab417","analyzedAt":"2026-08-15T13:25:18.241Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}