paperclipai/paperclip · error · DeliveryClaimUnavailableError

question_response_delivery_claim_unavailable

Error message

question_response_delivery_claim_unavailable

What it means

DeliveryClaimUnavailableError from withClaimLease: the claim ownership check against the database failed (an exception occurred while verifying rows.length === 1). The delivery's claim lease could not be confirmed, so the operation aborts to avoid two workers processing the same delivery. It is deliberately thrown instead of proceeding on uncertain ownership.

Solutions

  1. Retry the delivery operation after a short backoff — the error signals an uncertain claim, not a permanent failure
  2. Verify database connectivity and check server logs for the correlated 'question response claim ownership check failed' warning
  3. Check for lock contention or long transactions holding the delivery row
  4. If persistent, inspect DB health (max_connections, statement_timeout) and the claim lease query

Example fix

// before
await withClaimLease(deliveryId, doDeliver); // throws on transient DB hiccup
// after
await retry(
  { retries: 3, factor: 2 },
  () => withClaimLease(deliveryId, doDeliver),
  { shouldRetry: (e) => e instanceof DeliveryClaimUnavailableError },
);
Defensive patterns

Strategy: retry

Validate before calling

// Pre-check DB reachability before delivery batch
const ok = await db.execute(sql`SELECT 1`).then(() => true, () => false);
if (!ok) await waitForDbHealth();

Type guard

function isDeliveryClaimUnavailable(e) {
  return e instanceof Error && (e.name === "DeliveryClaimUnavailableError" || e.message === "question_response_delivery_claim_unavailable");
}

Try / catch

try {
  await withClaimLease(deliveryId, operation);
} catch (e) {
  if (isDeliveryClaimUnavailable(e)) {
    // uncertain ownership (db check failed): safe to retry with backoff
    await backoff(retryCount++);
    return retryDelivery(deliveryId);
  }
  throw e;
}

Prevention

When it happens

Trigger: Inside withClaimLease, the ownership SELECT/UPDATE throws (DB connection failure, timeout, serialization error) so ownsClaim cannot be determined; the catch block logs 'question response claim ownership check failed' and rethrows as DeliveryClaimUnavailableError.

Common situations: Transient Postgres connectivity loss during delivery; statement timeout on the claim check; DB failover mid-delivery; heavy lock contention on the delivery row.

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18). Data as JSON: /api/errors/90a65363213ce289. Report an issue: GitHub.

Appendix: source

Thrown at server/src/services/question-response-delivery.ts:693

        .from(issueQuestionResponseDeliveries)
        .where(
          and(
            eq(issueQuestionResponseDeliveries.id, delivery.id),
            eq(issueQuestionResponseDeliveries.status, "delivering"),
            eq(
              issueQuestionResponseDeliveries.attemptCount,
              delivery.attemptCount,
            ),
          ),
        )
        .limit(1)
        .then((rows) => rows.length === 1);
    } catch (error) {
      logger.warn(
        { err: error, deliveryId: delivery.id },
        "question response claim ownership check failed",
      );
      throw new DeliveryClaimUnavailableError();
    }
    if (!ownsClaim) throw new DeliveryClaimUnavailableError();
    if (operationError !== undefined) throw operationError;
    return result as T;
  }

  async function findDurableWakeRequest(input: {
    companyId: string;
    idempotencyKey: string;
  }) {
    const request = await db
      .select({
        agentId: agentWakeupRequests.agentId,
        id: agentWakeupRequests.id,
        runId: agentWakeupRequests.runId,
        status: agentWakeupRequests.status,
      })
      .from(agentWakeupRequests)

View on GitHub (pinned to 3f1d897a7c)