Troubleshooting Guide
Fresh Solutions for common Notion API issues.Quick Diagnostic Flowchart
Most Common Issues
1. "Object not found" Error
Symptoms:
- 404 error when accessing pages/databases
- API returns
object_not_foundcode
Causes & Solutions:
| Cause | Solution |
|---|---|
| Page not shared with integration | Open page → ... menu → Add connections → Select your integration |
| Wrong ID format | Ensure ID is correct (32 or 36 characters) |
| Page deleted/archived | Check trash, restore if needed |
| ID copied incorrectly | Re-copy from Notion URL |
Debug Script:
javascript
async function debugAccess(id) {
console.log(`Testing access to: ${id}`);
try {
// Try as page
const page = await notion.pages.retrieve({ page_id: id });
console.log('✅ Accessible as page:', page.url);
return { type: 'page', data: page };
} catch (e) {
console.log('❌ Not a page or no access');
}
try {
// Try as database
const db = await notion.databases.retrieve({ database_id: id });
console.log('✅ Accessible as database:', db.title[0]?.plain_text);
return { type: 'database', data: db };
} catch (e) {
console.log('❌ Not a database or no access');
}
console.log('\n⚠️ Cannot access resource. Please:');
console.log('1. Verify the ID is correct');
console.log('2. Share the page/database with your integration');
return null;
}2. Authentication Failures
Symptoms:
- 401 Unauthorized errors
- "API token is invalid" message
Checklist:
- [ ] API key starts with
secret_ - [ ] No extra whitespace in key
- [ ] Key is for correct workspace
- [ ] Key hasn't been regenerated
- [ ] Environment variable is loaded
Debug:
javascript
const apiKey = process.env.NOTION_API_KEY;
console.log('Key loaded:', !!apiKey);
console.log('Key length:', apiKey?.length);
console.log('Starts with secret_:', apiKey?.startsWith('secret_'));
console.log('Has whitespace:', apiKey !== apiKey?.trim());
// Test authentication
try {
const response = await notion.users.me({});
console.log('✅ Authenticated as:', response.name);
} catch (error) {
console.log('❌ Auth failed:', error.message);
}3. Property Validation Errors
Symptoms:
- 400 Bad Request
- "body.properties.X failed validation"
Common Mistakes:
javascript
// ❌ Wrong: Plain string for title
properties: {
Name: 'My Title'
}
// ✅ Correct: Proper title structure
properties: {
Name: {
title: [{ text: { content: 'My Title' } }]
}
}javascript
// ❌ Wrong: Wrong property name (case-sensitive)
properties: {
status: { select: { name: 'Done' } } // lowercase 's'
}
// ✅ Correct: Exact property name
properties: {
Status: { select: { name: 'Done' } } // uppercase 'S'
}javascript
// ❌ Wrong: Select option doesn't exist
properties: {
Status: { select: { name: 'Finished' } } // Not in options
}
// ✅ Correct: Use existing option name
properties: {
Status: { select: { name: 'Done' } } // Must match exactly
}Verify Property Names:
javascript
async function getPropertyNames(databaseId) {
const db = await notion.databases.retrieve({ database_id: databaseId });
console.log('Properties:');
for (const [name, config] of Object.entries(db.properties)) {
console.log(` "${name}" - type: ${config.type}`);
if (config.type === 'select' || config.type === 'multi_select') {
const options = config[config.type].options;
console.log(' Options:', options.map(o => o.name).join(', '));
}
}
}4. Rate Limiting
Symptoms:
- 429 Too Many Requests
- Requests failing in batches
- Intermittent failures
Solutions:
javascript
// Simple delay between requests
async function safeRequest(fn) {
const result = await fn();
await new Promise(r => setTimeout(r, 350)); // 350ms delay
return result;
}
// Process items with throttling
async function processItems(items, operation) {
const results = [];
for (const item of items) {
const result = await safeRequest(() => operation(item));
results.push(result);
}
return results;
}5. Empty Query Results
Symptoms:
- Query returns empty results array
- Filter doesn't match expected items
Debug:
javascript
async function debugQuery(databaseId, filter) {
// First, query without filter
const allResults = await notion.databases.query({
database_id: databaseId,
page_size: 5
});
console.log('Total pages (sample):', allResults.results.length);
if (allResults.results.length > 0) {
const sample = allResults.results[0];
console.log('\nSample page properties:');
for (const [name, value] of Object.entries(sample.properties)) {
console.log(` ${name}:`, JSON.stringify(value).slice(0, 100));
}
}
// Now try with filter
const filtered = await notion.databases.query({
database_id: databaseId,
filter
});
console.log('\nFiltered results:', filtered.results.length);
console.log('Filter used:', JSON.stringify(filter, null, 2));
}Common Filter Issues:
javascript
// ❌ Wrong: Using 'text' instead of specific type
filter: {
property: 'Name',
text: { contains: 'test' } // Wrong for title property
}
// ✅ Correct: Use 'title' for title properties
filter: {
property: 'Name',
title: { contains: 'test' }
}javascript
// ❌ Wrong: Using 'text' for rich_text
filter: {
property: 'Description',
text: { contains: 'test' } // Should be 'rich_text'
}
// ✅ Correct
filter: {
property: 'Description',
rich_text: { contains: 'test' }
}6. Blocks Not Appearing
Symptoms:
- Blocks created but not visible
- Content missing from page
Causes:
| Cause | Solution |
|---|---|
| Wrong page ID | Verify ID is for page, not database |
| Blocks in wrong format | Check block structure |
| Rate limit during creation | Add delays, verify each block |
| Nested too deep | Max 2 levels when creating |
Verify Blocks:
javascript
async function verifyBlocks(pageId) {
const response = await notion.blocks.children.list({
block_id: pageId,
page_size: 100
});
console.log('Blocks in page:', response.results.length);
for (const block of response.results) {
console.log(` ${block.type}:`, block.id);
if (block.has_children) {
const children = await notion.blocks.children.list({
block_id: block.id
});
console.log(` Children: ${children.results.length}`);
}
}
}7. Webhook Not Receiving Events
Symptoms:
- Webhook registered but no events
- Verification challenge not received
Checklist:
- [ ] HTTPS endpoint (not HTTP)
- [ ] Endpoint publicly accessible
- [ ] Correct response to verification challenge
- [ ] Firewall allows Notion IPs
- [ ] Response within 30 seconds
Test Endpoint:
javascript
// Test endpoint locally
const express = require('express');
const app = express();
app.use(express.raw({ type: 'application/json' }));
app.post('/webhook', (req, res) => {
const event = JSON.parse(req.body.toString());
console.log('Received event:', event.type);
if (event.type === 'verification') {
console.log('Verification challenge:', event.challenge);
return res.json({ challenge: event.challenge });
}
res.status(200).send('OK');
});
app.listen(3000, () => console.log('Listening on 3000'));8. SDK Type Errors
Symptoms:
- TypeScript errors with SDK
- Unexpected undefined values
Common Patterns:
javascript
// Safe property access
const title = page.properties.Name?.title?.[0]?.plain_text || 'Untitled';
const status = page.properties.Status?.select?.name || null;
const tags = page.properties.Tags?.multi_select?.map(t => t.name) || [];
// Type checking
function extractPageData(page) {
const props = page.properties;
return {
// Title - always check array
title: props.Name?.title?.[0]?.plain_text ?? '',
// Select - check for null
status: props.Status?.select?.name ?? null,
// Multi-select - default to empty array
tags: props.Tags?.multi_select?.map(t => t.name) ?? [],
// Number - default to 0 or null
priority: props.Priority?.number ?? 0,
// Date - check for date object
dueDate: props['Due Date']?.date?.start ?? null,
// Checkbox - default to false
done: props.Done?.checkbox ?? false,
// People - extract names
assignees: props.Assignee?.people?.map(p => p.name) ?? []
};
}Debug Environment Setup
javascript
// debug.js - Comprehensive debug script
require('dotenv').config();
const { Client, isNotionClientError } = require('@notionhq/client');
async function runDiagnostics() {
console.log('🔍 Notion API Diagnostics\n');
// 1. Check environment
console.log('1. Environment Variables');
console.log(' NOTION_API_KEY:', process.env.NOTION_API_KEY ? '✅ Set' : '❌ Missing');
console.log(' NOTION_DATABASE_ID:', process.env.NOTION_DATABASE_ID ? '✅ Set' : '❌ Missing');
if (!process.env.NOTION_API_KEY) {
console.log('\n❌ Cannot continue without API key');
return;
}
const notion = new Client({ auth: process.env.NOTION_API_KEY });
// 2. Test authentication
console.log('\n2. Authentication');
try {
const me = await notion.users.me({});
console.log(' ✅ Authenticated as:', me.name);
console.log(' Bot ID:', me.id);
} catch (error) {
console.log(' ❌ Auth failed:', error.message);
return;
}
// 3. Test database access
if (process.env.NOTION_DATABASE_ID) {
console.log('\n3. Database Access');
try {
const db = await notion.databases.retrieve({
database_id: process.env.NOTION_DATABASE_ID
});
console.log(' ✅ Database:', db.title[0]?.plain_text);
console.log(' Properties:', Object.keys(db.properties).join(', '));
} catch (error) {
console.log(' ❌ Database access failed:', error.message);
}
}
// 4. Test search
console.log('\n4. Search Capability');
try {
const search = await notion.search({ query: '', page_size: 1 });
console.log(' ✅ Can search, found:', search.results.length, 'items');
} catch (error) {
console.log(' ❌ Search failed:', error.message);
}
console.log('\n✅ Diagnostics complete');
}
runDiagnostics().catch(console.error);Getting Help
If issues persist:
- Check Notion Status: https://status.notion.so/
- Review API Changelog: https://developers.notion.com/changelog
- Search Notion Community: https://www.notion.so/community
- Include in Bug Reports:
- Request ID (from error response)
- API version used
- Full error message
- Minimal reproduction code