paperclipai/paperclip · error

actorUserId is required to respond to an interaction on beha

Error message

actorUserId is required to respond to an interaction on behalf of a board user

What it means

respondInteraction was invoked without an actorUserId. Resolving an issue-thread interaction is a board-user action, so the host requires a human actor to attribute the response to before re-verifying their membership.

Source

Thrown at server/src/services/plugin-host-services.ts:2505

        });
        return interaction as any;
      },
      async listInteractions(params) {
        const companyId = ensureCompanyId(params.companyId);
        await ensurePluginAvailableForCompany(companyId);
        if (!inCompany(await issues.getById(params.issueId), companyId)) return [];
        return (await interactions.listForIssue(params.issueId)) as any;
      },
      async respondInteraction(params) {
        const companyId = ensureCompanyId(params.companyId);
        await ensurePluginAvailableForCompany(companyId);
        const issue = requireInCompany("Issue", await issues.getById(params.issueId), companyId);
        // Resolving an interaction is a board-user action (the web app's
        // interaction-resolve routes are board-only). The host re-verifies the
        // paired user is an active human member at apply time and never trusts
        // the plugin-supplied identity — matching the createComment bar.
        if (!params.actorUserId) {
          throw new Error("actorUserId is required to respond to an interaction on behalf of a board user");
        }
        await requireActiveHumanMember(companyId, params.actorUserId);

        const current = await interactions.getById(params.interactionId);
        if (!current || current.issueId !== issue.id || current.companyId !== companyId) {
          throw new Error(`Interaction "${params.interactionId}" not found for this issue`);
        }
        // Idempotent replay: an already-resolved interaction converges without
        // re-applying, so a duplicate button tap from chat is a safe no-op.
        if (current.status !== "pending") {
          return { interaction: current as any, applied: false };
        }

        const actor = { userId: params.actorUserId };
        let resolved: typeof current;
        let continuationTarget = {
          id: issue.id,
          assigneeAgentId: issue.assigneeAgentId,

View on GitHub (pinned to a7e689b3c3)

Solutions

  1. Include actorUserId in the respond-to-interaction call when acting on behalf of a board user; obtain it from the interaction request context.
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at server/src/services/plugin-host-services.ts:2496 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of paperclipai/paperclip@a7e689b3c3 (2026-08-18). Data as JSON: /api/errors/9929ef59d7543dc9. Report an issue: GitHub.