返回 Skill 列表
extension
分类: 开发与工程无需 API Key

documenso-common-errors

诊断并解决常见的Documenso API错误和问题。当遇到Documenso错误、调试集成问题或排查失败操作时使用。可以通过诸如“documenso error”、“documenso 401”、“documenso failed”、“fix documenso”、“documenso not working”等短语触发。

person作者: jakexiaohubgithub

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

| Status | Error | Common Cause | Quick Fix | |--------|-------|--------------|-----------| | 400 | Bad Request | Invalid parameters | Check request body format | | 401 | Unauthorized | Invalid/missing API key | Verify DOCUMENSO_API_KEY | | 403 | Forbidden | Insufficient permissions | Use team API key | | 404 | Not Found | Resource doesn't exist | Verify ID is correct | | 409 | Conflict | Duplicate resource | Handle existing resource | | 422 | Unprocessable | Validation failed | Check field values | | 429 | Rate Limited | Too many requests | Implement backoff | | 500 | Server Error | Documenso issue | Retry 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

Next Steps

For comprehensive debugging, see documenso-debug-bundle.