paperclipai/paperclip · error

External object refresh claim did not return a refresh token

Error message

External object refresh claim did not return a refresh token

What it means

Invariant guard in externalObjectService's refresh path: claimObjectRefresh reported the refresh as claimed but produced no refresh token. Without the token the caller cannot complete/commit the refresh, so the claim is treated as malformed rather than proceeding token-less.

Source

Thrown at server/src/services/external-objects.ts:996

      return { object: toObjectPayload(object, now), refreshed: false, reason: "backoff" as const };
    }

    const refreshKey = `${object.companyId}:${object.id}`;
    const existingRefresh = objectRefreshesInFlight.get(refreshKey);
    if (existingRefresh) return existingRefresh;

    const claimed = await claimObjectRefresh(object, input, now);
    if (!claimed) {
      const latest = await db
        .select()
        .from(externalObjects)
        .where(and(eq(externalObjects.id, object.id), eq(externalObjects.companyId, object.companyId)))
        .then((rows) => rows[0] ?? null);
      if (!latest) throw notFound("External object not found");
      return { object: toObjectPayload(latest, now), refreshed: false, reason: "refresh_in_progress" as const };
    }
    if (!claimed.refreshToken) {
      throw new Error("External object refresh claim did not return a refresh token");
    }

    const stopRenewingRefreshLease = startRefreshLeaseRenewal(object, claimed.refreshToken);
    const refresh = resolveObjectRefresh(object, input, now, claimed.refreshToken).finally(() => {
      stopRenewingRefreshLease();
      objectRefreshesInFlight.delete(refreshKey);
    });
    objectRefreshesInFlight.set(refreshKey, refresh);
    return refresh;
  }

  async function refreshIssueObjects(issueId: string, input: {
    companyId: string;
    objectIds?: string[];
    actor?: Pick<LogActivityInput, "actorType" | "actorId" | "agentId" | "runId">;
  }) {
    if (!(await isEnabled())) return [];
    const groups = await listForIssue(issueId);

View on GitHub (pinned to 120ae5428f)

Solutions

  1. Check the external object provider's claim flow; ensure a refresh token is returned and stored.
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at server/src/services/external-objects.ts:996 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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