Skip to content

Error Codes Reference

Fresh All Notion API error codes with causes and solutions.

Error Response Structure

javascript
{
  "object": "error",
  "status": 400,
  "code": "validation_error",
  "message": "Description of the error",
  "request_id": "xxx-xxx-xxx"
}

HTTP Status Codes

StatusMeaningCommon Causes
400Bad RequestInvalid request body, missing required fields
401UnauthorizedInvalid or missing API key
403ForbiddenInsufficient permissions
404Not FoundResource doesn't exist or not accessible
409ConflictResource already exists
429Too Many RequestsRate limited
500Internal Server ErrorNotion server issue
502Bad GatewayNotion infrastructure issue
503Service UnavailableNotion temporarily unavailable
504Gateway TimeoutRequest took too long

Error Codes by Category

Detailed Error Reference

Authentication Errors (401)

unauthorized

Cause: Invalid or missing API key.

javascript
{
  "status": 401,
  "code": "unauthorized",
  "message": "API token is invalid."
}

Solutions:

  1. Verify API key starts with secret_
  2. Check for extra whitespace
  3. Regenerate key in integration settings
  4. Ensure key is for correct workspace
javascript
// Wrong
const notion = new Client({ auth: 'secret_xxx ' }); // trailing space

// Correct
const notion = new Client({ auth: process.env.NOTION_API_KEY.trim() });

Authorization Errors (403)

restricted_resource

Cause: Integration lacks permission for this resource.

javascript
{
  "status": 403,
  "code": "restricted_resource",
  "message": "Cannot access this resource."
}

Solutions:

  1. Share the page/database with your integration
  2. Enable required capabilities in integration settings
  3. Check parent page permissions

object_not_found

Cause: Resource doesn't exist OR integration doesn't have access.

javascript
{
  "status": 404,
  "code": "object_not_found",
  "message": "Could not find page with ID: xxx"
}

Solutions:

  1. Verify the ID is correct
  2. Add integration connection to the page
  3. Check if page was deleted or archived
  4. Ensure ID format is correct (with or without dashes)
javascript
// Debug: Check if integration can see the resource
try {
  await notion.pages.retrieve({ page_id: id });
} catch (error) {
  if (error.code === 'object_not_found') {
    console.log('Page not shared with integration or does not exist');
  }
}

Validation Errors (400)

validation_error

Cause: Request body doesn't match expected schema.

javascript
{
  "status": 400,
  "code": "validation_error",
  "message": "body failed validation: body.properties.Title.title should be defined"
}

Common Causes:

  • Missing required properties
  • Wrong property type
  • Invalid enum value
  • Exceeding limits

Solutions:

javascript
// Wrong: Missing title wrapper
properties: {
  Name: { text: { content: 'Title' } }
}

// Correct: Title property needs title array
properties: {
  Name: {
    title: [{ text: { content: 'Title' } }]
  }
}
javascript
// Wrong: Select value as string
properties: {
  Status: 'Done'
}

// Correct: Select with proper structure
properties: {
  Status: { select: { name: 'Done' } }
}

invalid_request

Cause: Request structure is invalid.

javascript
{
  "status": 400,
  "code": "invalid_request",
  "message": "Invalid request: Cannot update a page that was created by an integration."
}

Common Causes:

  • Attempting unsupported operations
  • Wrong endpoint for the action
  • Invalid parameter combinations

invalid_request_url

Cause: URL contains invalid characters or format.

javascript
{
  "status": 400,
  "code": "invalid_request_url",
  "message": "Invalid request URL."
}

Solutions:

  1. Encode special characters in URLs
  2. Verify ID format
  3. Check for typos in endpoint

invalid_json

Cause: Request body is not valid JSON.

javascript
{
  "status": 400,
  "code": "invalid_json",
  "message": "Error parsing JSON body."
}

Solutions:

  1. Validate JSON syntax
  2. Check for trailing commas
  3. Ensure proper encoding

Rate Limit Errors (429)

rate_limited

Cause: Too many requests in a short period.

javascript
{
  "status": 429,
  "code": "rate_limited",
  "message": "Rate limited. Try again later.",
  "headers": {
    "retry-after": "1"
  }
}

Solutions:

javascript
const { isNotionClientError, APIErrorCode } = require('@notionhq/client');

async function withRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (isNotionClientError(error) && error.code === APIErrorCode.RateLimited) {
        const retryAfter = parseInt(error.headers?.['retry-after'] || '1');
        console.log(`Rate limited. Waiting ${retryAfter}s...`);
        await new Promise(r => setTimeout(r, retryAfter * 1000));
        continue;
      }
      throw error;
    }
  }
}

Prevention:

  • Limit to 3 requests per second
  • Implement request queuing
  • Use exponential backoff
  • Batch operations where possible

Server Errors (500, 502, 503, 504)

internal_server_error

Cause: Notion server encountered an error.

javascript
{
  "status": 500,
  "code": "internal_server_error",
  "message": "An unexpected error occurred."
}

Solutions:

  1. Retry with exponential backoff
  2. Check Notion status page
  3. Report if persistent

service_unavailable

Cause: Notion service is temporarily down.

Solutions:

  1. Wait and retry
  2. Implement circuit breaker pattern
  3. Queue requests for later

Conflict Errors (409)

conflict_error

Cause: Resource state conflict, often due to concurrent modifications.

javascript
{
  "status": 409,
  "code": "conflict_error",
  "message": "Cannot perform this operation due to a conflict."
}

Solutions:

  1. Refetch the resource and retry
  2. Implement optimistic locking
  3. Add transaction-like logic

Error Handling Best Practices

SDK Error Checking

javascript
const {
  Client,
  isNotionClientError,
  APIErrorCode
} = require('@notionhq/client');

try {
  await notion.pages.retrieve({ page_id: 'xxx' });
} catch (error) {
  if (isNotionClientError(error)) {
    switch (error.code) {
      case APIErrorCode.Unauthorized:
        // Handle auth error
        break;
      case APIErrorCode.ObjectNotFound:
        // Handle not found
        break;
      case APIErrorCode.RateLimited:
        // Handle rate limit
        break;
      case APIErrorCode.ValidationError:
        // Handle validation
        console.log('Validation error:', error.message);
        break;
      default:
        // Handle other Notion errors
        console.error('Notion error:', error.code, error.message);
    }
  } else {
    // Handle non-Notion errors (network, etc.)
    console.error('Error:', error);
  }
}

Comprehensive Error Handler

javascript
function handleNotionError(error) {
  if (!isNotionClientError(error)) {
    return {
      type: 'unknown',
      message: error.message,
      retry: false
    };
  }

  const errorConfig = {
    [APIErrorCode.Unauthorized]: {
      type: 'auth',
      message: 'Check your API key',
      retry: false
    },
    [APIErrorCode.ObjectNotFound]: {
      type: 'not_found',
      message: 'Resource not found or not accessible',
      retry: false
    },
    [APIErrorCode.RateLimited]: {
      type: 'rate_limit',
      message: 'Too many requests',
      retry: true,
      delay: parseInt(error.headers?.['retry-after'] || '1') * 1000
    },
    [APIErrorCode.ValidationError]: {
      type: 'validation',
      message: error.message,
      retry: false
    },
    internal_server_error: {
      type: 'server',
      message: 'Notion server error',
      retry: true,
      delay: 5000
    },
    service_unavailable: {
      type: 'server',
      message: 'Notion temporarily unavailable',
      retry: true,
      delay: 10000
    }
  };

  return errorConfig[error.code] || {
    type: 'unknown',
    message: error.message,
    retry: false
  };
}

Quick Troubleshooting

ErrorFirst Thing to Check
401 UnauthorizedAPI key format and validity
403 ForbiddenIntegration permissions and capabilities
404 Not FoundPage shared with integration?
400 ValidationProperty names and types
429 Rate LimitedAdd delays between requests
500 Server ErrorRetry later, check status.notion.so

See Also

Built with VitePress | Powered by Claude AI