# Errors, Retries, and Debugging

Use this reference for robust Notion API calls, rate limits, timeouts, and payload debugging.

## Structured Exceptions

Import specific errors when caller behavior should differ by failure type:

```python
from notionhelper import (
    AuthError,
    NotFoundError,
    RateLimitError,
    TimeoutError,
    ValidationError,
    NotionAPIError,
)
```

Exception metadata:

- `status_code`
- `request_path`
- `notion_code`
- `message`

Example:

```python
try:
    page = helper.get_page(page_id)
except AuthError:
    raise RuntimeError("Check NOTION_TOKEN and integration sharing.")
except NotFoundError as err:
    raise RuntimeError(f"Notion object not found or not shared: {err.request_path}") from err
except ValidationError as err:
    raise RuntimeError(f"Invalid Notion payload: {err.message}") from err
```

## Retry Policy

Defaults retry transient statuses `{429, 500, 502, 503, 504}`, timeouts, and connection errors.

Configure globally:

```python
from notionhelper import RetryPolicy

helper = NotionHelper(
    os.environ["NOTION_TOKEN"],
    retry_policy=RetryPolicy(
        max_retries=5,
        base_delay=0.5,
        max_delay=20.0,
        jitter_ratio=0.2,
        timeout=15.0,
    ),
)
```

Override per streaming query:

```python
policy = RetryPolicy(max_retries=2, timeout=10.0)
pages = list(helper.iter_data_source_pages(data_source_id, retry_policy=policy))
```

`Retry-After` is honored when present. Delay values are clamped to safe minimums and maximums.

## Debug Logging

Enable debug request logging without logging secrets:

```python
import logging

logging.basicConfig(level=logging.DEBUG)
helper = NotionHelper(os.environ["NOTION_TOKEN"], debug=True)
```

For append validation failures, `_make_request` logs the likely failing `children[index]` block when Notion includes that index in the error message.

## Common Failure Diagnosis

- 401/403: bad token, missing capabilities, or object not shared with integration.
- 404: invalid ID or object not shared with integration.
- 400/422: payload shape mismatch, wrong property type, invalid select option, or using a `database_id` where a `data_source_id` is required.
- 429: rate limit; increase retries/backoff or reduce batch/query frequency.
- Timeout: reduce page size, stream results, or increase `request_timeout`.

## Testing Guidance

Mock `_make_request` for package-level behavior. Mock `requests.get/post/patch` only when testing retry classification itself.

```python
from unittest.mock import patch
from notionhelper import NotionHelper

with patch.object(NotionHelper, "_make_request", return_value={"id": "page-id"}):
    result = helper.new_page_to_data_source(data_source_id, props)
```
