or run

tessl search
Log in

documenso-common-errors

tessl install github:jeremylongshore/claude-code-plugins-plus-skills --skill documenso-common-errors

github.com/jeremylongshore/claude-code-plugins-plus-skills

Diagnose and resolve common Documenso API errors and issues. Use when encountering Documenso errors, debugging integration issues, or troubleshooting failed operations. Trigger with phrases like "documenso error", "documenso 401", "documenso failed", "fix documenso", "documenso not working".

Review Score

88%

Validation Score

13/16

Implementation Score

85%

Activation Score

90%

Documenso Common Errors

Overview

Quick reference for diagnosing and resolving common Documenso API errors.

Prerequisites

  • Basic understanding of Documenso SDK
  • Access to application logs
  • API key available

Error Reference Table

StatusErrorCommon CauseQuick Fix
400Bad RequestInvalid parametersCheck request body format
401UnauthorizedInvalid/missing API keyVerify DOCUMENSO_API_KEY
403ForbiddenInsufficient permissionsUse team API key
404Not FoundResource doesn't existVerify ID is correct
409ConflictDuplicate resourceHandle existing resource
422UnprocessableValidation failedCheck field values
429Rate LimitedToo many requestsImplement backoff
500Server ErrorDocumenso issueRetry with backoff

Detailed Error Scenarios

Error: 401 Unauthorized

Symptoms:

SDKError: Unauthorized
Status: 401

Causes and Solutions:

// Cause 1: Missing API key
// Solution: Set environment variable
export DOCUMENSO_API_KEY="your-api-key"

// Cause 2: Invalid API key format
// Wrong: API key with extra whitespace
const apiKey = " dcs_abc123 ";  // Bad
const apiKey = "dcs_abc123";     // Good

// Cause 3: Expired or revoked key
// Solution: Generate new key in Documenso dashboard

// Cause 4: Wrong environment
// Solution: Use correct key for environment
const client = new Documenso({
  apiKey: process.env.DOCUMENSO_API_KEY,
  serverURL: process.env.DOCUMENSO_BASE_URL,  // Match key to URL
});

Error: 403 Forbidden

Symptoms:

SDKError: Forbidden
Status: 403

Causes and Solutions:

// Cause 1: Personal API key used for team resources
// Solution: Use team API key for team documents
// Get team API key from: Team Settings > API Tokens

// Cause 2: Accessing another user's resource
// Solution: Verify you own the document
const doc = await client.documents.getV0({ documentId });
// Check doc.userId matches your user

// Cause 3: Document in terminal state
// Solution: Cannot modify completed/cancelled documents
if (doc.status === "COMPLETED" || doc.status === "CANCELLED") {
  console.log("Cannot modify document in terminal state");
  // Create new document instead
}

Error: 404 Not Found

Symptoms:

SDKError: Not Found
Status: 404

Causes and Solutions:

// Cause 1: Wrong document ID
// Solution: Verify ID format and existence
async function safeGetDocument(documentId: string) {
  try {
    return await client.documents.getV0({ documentId });
  } catch (error: any) {
    if (error.statusCode === 404) {
      console.log(`Document ${documentId} not found`);
      return null;
    }
    throw error;
  }
}

// Cause 2: Document deleted
// Solution: Check if document was deleted

// Cause 3: Using v1 ID with v2 API (or vice versa)
// Solution: IDs have different formats between versions
// v1: numeric IDs like "12345"
// v2: prefixed IDs like "doc_abc123"

Error: 409 Conflict

Symptoms:

SDKError: Conflict
Status: 409

Causes and Solutions:

// Cause 1: Duplicate recipient email
// Solution: Update existing or skip
async function addOrUpdateRecipient(
  documentId: string,
  email: string,
  name: string
) {
  try {
    return await client.documentsRecipients.createV0({
      documentId,
      email,
      name,
      role: "SIGNER",
    });
  } catch (error: any) {
    if (error.statusCode === 409) {
      // Recipient exists - find and update
      const doc = await client.documents.getV0({ documentId });
      const existing = doc.recipients?.find(r => r.email === email);
      if (existing) {
        return await client.documentsRecipients.updateV0({
          documentId,
          recipientId: existing.id!,
          name,  // Update name
        });
      }
    }
    throw error;
  }
}

// Cause 2: Template with same name
// Solution: Use unique name or update existing

Error: 422 Unprocessable Entity

Symptoms:

SDKError: Unprocessable Entity
Status: 422

Causes and Solutions:

// Cause 1: Invalid field position (off-page)
// Solution: Check page dimensions
const fieldConfig = {
  page: 1,
  positionX: 100,  // Must be 0 < x < pageWidth
  positionY: 600,  // Must be 0 < y < pageHeight
  width: 200,      // x + width must be < pageWidth
  height: 60,      // y + height must be < pageHeight
};

// Letter size: 612 x 792 points
// A4 size: 595 x 842 points

// Cause 2: Invalid email format
// Solution: Validate before sending
function isValidEmail(email: string): boolean {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}

// Cause 3: Missing required fields
// Solution: Check all required parameters
const recipient = await client.documentsRecipients.createV0({
  documentId,      // Required
  email,           // Required
  name,            // Required
  role: "SIGNER",  // Required
});

// Cause 4: Invalid file type
// Solution: Only PDF files are supported

Error: 429 Rate Limited

Symptoms:

SDKError: Too Many Requests
Status: 429

Solution:

// Implement exponential backoff
async function withBackoff<T>(
  operation: () => Promise<T>,
  maxRetries = 5
): Promise<T> {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await operation();
    } catch (error: any) {
      if (error.statusCode !== 429 || attempt === maxRetries - 1) {
        throw error;
      }

      // Check Retry-After header if available
      const retryAfter = error.headers?.["retry-after"];
      const delay = retryAfter
        ? parseInt(retryAfter) * 1000
        : Math.pow(2, attempt) * 1000;

      console.log(`Rate limited. Waiting ${delay}ms...`);
      await new Promise(r => setTimeout(r, delay));
    }
  }
  throw new Error("Max retries exceeded");
}

// Use queue for bulk operations
import PQueue from "p-queue";

const queue = new PQueue({
  concurrency: 2,
  interval: 1000,
  intervalCap: 5,
});

async function queuedCreate(data: any) {
  return queue.add(() => client.documents.createV0(data));
}

Error: 500 Internal Server Error

Symptoms:

SDKError: Internal Server Error
Status: 500

Solution:

// Retry with exponential backoff (server errors are usually transient)
async function retryServerErrors<T>(
  operation: () => Promise<T>
): Promise<T> {
  for (let attempt = 0; attempt < 3; attempt++) {
    try {
      return await operation();
    } catch (error: any) {
      if (error.statusCode < 500 || attempt === 2) {
        throw error;
      }

      const delay = Math.pow(2, attempt) * 1000;
      console.log(`Server error. Retrying in ${delay}ms...`);
      await new Promise(r => setTimeout(r, delay));
    }
  }
  throw new Error("Max retries exceeded");
}

// If persistent, check Documenso status
// https://status.documenso.com

File Upload Errors

// Error: File too large
// Solution: Check file size before upload
const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB

async function uploadWithSizeCheck(pdfPath: string) {
  const stats = await fs.promises.stat(pdfPath);
  if (stats.size > MAX_FILE_SIZE) {
    throw new Error(`File exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit`);
  }
  return openAsBlob(pdfPath);
}

// Error: Invalid file type
// Solution: Verify PDF format
import { fileTypeFromFile } from "file-type";

async function verifyPdf(filePath: string) {
  const type = await fileTypeFromFile(filePath);
  if (type?.mime !== "application/pdf") {
    throw new Error("Only PDF files are supported");
  }
}

Webhook Errors

// Error: Webhook not receiving events
// Checklist:
// 1. Webhook URL is HTTPS
// 2. Endpoint returns 200 within 30 seconds
// 3. Correct events are subscribed
// 4. Secret is correctly configured

// Error: Signature verification failing
function verifyWebhookSignature(
  payload: string,
  receivedSecret: string
): boolean {
  const expectedSecret = process.env.DOCUMENSO_WEBHOOK_SECRET;
  // Documenso sends secret in X-Documenso-Secret header
  return receivedSecret === expectedSecret;
}

Debugging Checklist

  1. Check API Key:

    echo $DOCUMENSO_API_KEY | head -c 10
    # Should show: dcs_xxx...
  2. Verify Endpoint:

    curl -H "Authorization: Bearer $DOCUMENSO_API_KEY" \
      https://app.documenso.com/api/v2/documents
  3. Enable Debug Logging:

    const client = new Documenso({
      apiKey: process.env.DOCUMENSO_API_KEY,
      debugLogger: console,
    });
  4. Check Document Status:

    const doc = await client.documents.getV0({ documentId });
    console.log(`Status: ${doc.status}`);
    console.log(`Recipients: ${doc.recipients?.length}`);

Output

  • Error identified and categorized
  • Root cause determined
  • Solution implemented
  • Retry logic in place

Resources

  • Documenso API Reference
  • Status Page
  • GitHub Issues

Next Steps

For comprehensive debugging, see documenso-debug-bundle.