nodestash

Error Handling

Understand error responses and handle them gracefully

All API errors follow a consistent JSON format with an error code, message, and optional field-level details.

Error Response Format

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": [
      {
        "field": "email",
        "message": "Invalid email format"
      }
    ]
  },
  "meta": {
    "request_id": "req_abc123def456ghi789jkl012"
  }
}
FieldTypeDescription
error.codestringMachine-readable error code
error.messagestringHuman-readable description
error.detailsarrayField-level errors (for validation failures)
meta.request_idstringUnique request ID for debugging

Always include meta.request_id when contacting support — it helps us trace the exact request.

Error Codes

StatusCodeDescription
400VALIDATION_ERRORRequest body or query parameter validation failed
401MISSING_AUTHNo Authorization header provided
401INVALID_API_KEYAPI key is invalid, revoked, or expired
403INSUFFICIENT_SCOPEAPI key lacks the required scope
404NOT_FOUNDResource does not exist
409CONFLICTDuplicate resource (e.g., email or domain already exists)
422UNPROCESSABLE_ENTITYReferenced resource doesn't exist (e.g., invalid company_id)
429RATE_LIMITEDRate limit exceeded
500INTERNAL_ERRORUnexpected server error

Validation Errors

Validation errors include a details array with field-level messages:

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": [
      {
        "field": "email",
        "message": "Invalid email format"
      },
      {
        "field": "tags",
        "message": "Array must contain at most 20 element(s)"
      }
    ]
  },
  "meta": {
    "request_id": "req_abc123def456ghi789jkl012"
  }
}

Conflict Errors

Conflict errors occur when you try to create a resource that violates a uniqueness constraint:

{
  "error": {
    "code": "CONFLICT",
    "message": "A contact with this email already exists in this workspace"
  },
  "meta": {
    "request_id": "req_abc123def456ghi789jkl012"
  }
}

Common conflicts:

  • Duplicate contact email within a workspace
  • Duplicate company domain within a workspace
  • Duplicate custom field slug per entity type

SDK Error Handling

The TypeScript SDK maps API errors to specific error classes:

import {
  NodeStash,
  ApiError,
  AuthenticationError,
  NotFoundError,
  ValidationError,
  RateLimitError,
} from '@nodestash/sdk'

const client = new NodeStash({ apiKey: 'nds_live_...' })

try {
  await client.contacts.create({ email: 'invalid' })
} catch (error) {
  if (error instanceof ValidationError) {
    console.log(error.message)
    for (const detail of error.details) {
      console.log(`  ${detail.field}: ${detail.message}`)
    }
  } else if (error instanceof AuthenticationError) {
    console.log('Check your API key')
  } else if (error instanceof NotFoundError) {
    console.log('Resource not found')
  } else if (error instanceof RateLimitError) {
    console.log(`Rate limited. Retry after ${error.retryAfter}s`)
  } else if (error instanceof ApiError) {
    console.log(`${error.code}: ${error.message}`)
    console.log(`Status: ${error.statusCode}`)
    console.log(`Request ID: ${error.requestId}`)
  }
}

Error Class Hierarchy

Error
└── NodeStashError           — Base SDK error
    └── ApiError             — API returned an error response
        ├── AuthenticationError  — 401 (invalid/missing key)
        ├── NotFoundError        — 404 (resource not found)
        ├── ValidationError      — 400/422 (validation failed)
        └── RateLimitError       — 429 (rate limited)

Error Properties

ClassProperties
ApiErrorcode, statusCode, requestId, details, message
AuthenticationErrorrequestId, message
NotFoundErrorrequestId, message
ValidationErrordetails[], requestId, message
RateLimitErrorretryAfter, requestId, message

Best Practices

  • Handle specific errors first — catch ValidationError, NotFoundError etc. before ApiError
  • Log the request ID — include meta.request_id or error.requestId in your logs
  • Don't retry 4xx errors — only retry on 429 (rate limit) and 5xx (server errors)
  • Display validation details — show users which fields have errors using error.details

On this page