or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

block-operations.mdclient-configuration.mdcomments.mddata-source-operations.mddatabase-operations.mderror-handling.mdfile-uploads.mdindex.mdoauth-authentication.mdpage-operations.mdpagination-helpers.mdsearch.mduser-management.md

error-handling.mddocs/

0

# Error Handling

1

2

Comprehensive error handling with specific error types and codes for different failure scenarios.

3

4

## Capabilities

5

6

### Error Types

7

8

The Notion SDK provides specific error classes for different types of failures.

9

10

```typescript { .api }

11

/**

12

* Union type of all possible errors from the Notion client

13

*/

14

type NotionClientError =

15

| APIResponseError

16

| UnknownHTTPResponseError

17

| RequestTimeoutError;

18

19

/**

20

* Check if an error is a Notion client error

21

* @param error - Error to check

22

* @returns True if error is from Notion client

23

*/

24

function isNotionClientError(error: unknown): error is NotionClientError;

25

```

26

27

### API Response Errors

28

29

Errors returned from the Notion API with specific error codes.

30

31

```typescript { .api }

32

/**

33

* Error thrown when API returns an error response

34

*/

35

class APIResponseError extends Error {

36

/** Error code from the API */

37

code: APIErrorCode;

38

/** HTTP status code */

39

status: number;

40

/** Additional error details */

41

headers: Record<string, string>;

42

/** Raw response body */

43

body: string;

44

}

45

46

/**

47

* Error codes returned by the Notion API

48

*/

49

enum APIErrorCode {

50

Unauthorized = "unauthorized";

51

RestrictedResource = "restricted_resource";

52

ObjectNotFound = "object_not_found";

53

RateLimited = "rate_limited";

54

InvalidJSON = "invalid_json";

55

InvalidRequestURL = "invalid_request_url";

56

InvalidRequest = "invalid_request";

57

ValidationError = "validation_error";

58

ConflictError = "conflict_error";

59

InternalServerError = "internal_server_error";

60

ServiceUnavailable = "service_unavailable";

61

}

62

```

63

64

**Usage Examples:**

65

66

```typescript

67

import { Client, APIErrorCode, isNotionClientError } from "@notionhq/client";

68

69

const notion = new Client({ auth: process.env.NOTION_TOKEN });

70

71

try {

72

const page = await notion.pages.retrieve({

73

page_id: "invalid-page-id",

74

});

75

} catch (error) {

76

if (isNotionClientError(error)) {

77

console.log(`Notion error: ${error.code}`);

78

79

if (error.code === APIErrorCode.ObjectNotFound) {

80

console.log("Page not found");

81

} else if (error.code === APIErrorCode.Unauthorized) {

82

console.log("Invalid token or insufficient permissions");

83

} else if (error.code === APIErrorCode.RateLimited) {

84

console.log("Rate limited - retry after delay");

85

}

86

} else {

87

console.log("Unknown error:", error);

88

}

89

}

90

```

91

92

### Client Errors

93

94

Errors generated by the client itself, not the API.

95

96

```typescript { .api }

97

/**

98

* Error codes for client-side errors

99

*/

100

enum ClientErrorCode {

101

RequestTimeout = "notionhq_client_request_timeout";

102

ResponseError = "notionhq_client_response_error";

103

}

104

105

/**

106

* Error thrown when request times out

107

*/

108

class RequestTimeoutError extends Error {

109

code: ClientErrorCode.RequestTimeout;

110

}

111

112

/**

113

* Error thrown for unknown HTTP response errors

114

*/

115

class UnknownHTTPResponseError extends Error {

116

code: ClientErrorCode.ResponseError;

117

/** HTTP status code */

118

status: number;

119

/** Response body */

120

body: string;

121

}

122

```

123

124

**Usage Examples:**

125

126

```typescript

127

import { Client, ClientErrorCode } from "@notionhq/client";

128

129

const notion = new Client({

130

auth: process.env.NOTION_TOKEN,

131

timeoutMs: 5000, // 5 second timeout

132

});

133

134

try {

135

const page = await notion.pages.retrieve({

136

page_id: "page-id",

137

});

138

} catch (error) {

139

if (isNotionClientError(error)) {

140

if (error.code === ClientErrorCode.RequestTimeout) {

141

console.log("Request timed out - try again");

142

} else if (error.code === ClientErrorCode.ResponseError) {

143

console.log(`HTTP error ${error.status}: ${error.body}`);

144

}

145

}

146

}

147

```

148

149

### Error Code Union Type

150

151

```typescript { .api }

152

/**

153

* Union of all error codes (API + Client)

154

*/

155

type NotionErrorCode = APIErrorCode | ClientErrorCode;

156

```

157

158

## Error Handling Patterns

159

160

### Basic Error Handling

161

162

```typescript

163

async function safePage Retrieval(pageId: string) {

164

try {

165

const page = await notion.pages.retrieve({ page_id: pageId });

166

return { success: true, page };

167

} catch (error) {

168

if (isNotionClientError(error)) {

169

return {

170

success: false,

171

error: error.code,

172

message: error.message

173

};

174

}

175

176

return {

177

success: false,

178

error: "unknown",

179

message: "Unknown error occurred"

180

};

181

}

182

}

183

```

184

185

### Retry with Exponential Backoff

186

187

```typescript

188

async function retryWithBackoff<T>(

189

operation: () => Promise<T>,

190

maxRetries: number = 3

191

): Promise<T> {

192

let lastError: Error;

193

194

for (let attempt = 0; attempt < maxRetries; attempt++) {

195

try {

196

return await operation();

197

} catch (error) {

198

lastError = error as Error;

199

200

if (isNotionClientError(error)) {

201

// Don't retry certain errors

202

if (error.code === APIErrorCode.Unauthorized ||

203

error.code === APIErrorCode.ObjectNotFound ||

204

error.code === APIErrorCode.InvalidRequest) {

205

throw error;

206

}

207

208

// Retry rate limited or server errors

209

if (error.code === APIErrorCode.RateLimited ||

210

error.code === APIErrorCode.InternalServerError ||

211

error.code === APIErrorCode.ServiceUnavailable ||

212

error.code === ClientErrorCode.RequestTimeout) {

213

214

const delay = Math.pow(2, attempt) * 1000; // Exponential backoff

215

await new Promise(resolve => setTimeout(resolve, delay));

216

continue;

217

}

218

}

219

220

throw error;

221

}

222

}

223

224

throw lastError!;

225

}

226

227

// Usage

228

const page = await retryWithBackoff(() =>

229

notion.pages.retrieve({ page_id: "page-id" })

230

);

231

```

232

233

### Detailed Error Information

234

235

```typescript

236

function handleNotionError(error: unknown) {

237

if (!isNotionClientError(error)) {

238

console.log("Non-Notion error:", error);

239

return;

240

}

241

242

console.log(`Error Code: ${error.code}`);

243

console.log(`Error Message: ${error.message}`);

244

245

if (error instanceof APIResponseError) {

246

console.log(`HTTP Status: ${error.status}`);

247

console.log(`Response Headers:`, error.headers);

248

console.log(`Response Body:`, error.body);

249

}

250

251

if (error instanceof UnknownHTTPResponseError) {

252

console.log(`HTTP Status: ${error.status}`);

253

console.log(`Response Body:`, error.body);

254

}

255

256

// Handle specific error codes

257

switch (error.code) {

258

case APIErrorCode.Unauthorized:

259

console.log("Check your API token and permissions");

260

break;

261

case APIErrorCode.RateLimited:

262

console.log("Slow down requests to avoid rate limiting");

263

break;

264

case APIErrorCode.ObjectNotFound:

265

console.log("The requested resource was not found");

266

break;

267

case APIErrorCode.ValidationError:

268

console.log("Request data failed validation");

269

break;

270

case ClientErrorCode.RequestTimeout:

271

console.log("Request timed out - consider increasing timeout");

272

break;

273

}

274

}

275

```

276

277

### Graceful Degradation

278

279

```typescript

280

async function getPageOrFallback(pageId: string) {

281

try {

282

return await notion.pages.retrieve({ page_id: pageId });

283

} catch (error) {

284

if (isNotionClientError(error)) {

285

if (error.code === APIErrorCode.ObjectNotFound) {

286

// Return a default page structure

287

return {

288

object: "page" as const,

289

id: pageId,

290

properties: {},

291

// ... other default properties

292

};

293

}

294

295

if (error.code === APIErrorCode.Unauthorized) {

296

throw new Error("Authentication required");

297

}

298

}

299

300

// Re-throw other errors

301

throw error;

302

}

303

}

304

```

305

306

## Types

307

308

```typescript { .api }

309

enum APIErrorCode {

310

Unauthorized = "unauthorized";

311

RestrictedResource = "restricted_resource";

312

ObjectNotFound = "object_not_found";

313

RateLimited = "rate_limited";

314

InvalidJSON = "invalid_json";

315

InvalidRequestURL = "invalid_request_url";

316

InvalidRequest = "invalid_request";

317

ValidationError = "validation_error";

318

ConflictError = "conflict_error";

319

InternalServerError = "internal_server_error";

320

ServiceUnavailable = "service_unavailable";

321

}

322

323

enum ClientErrorCode {

324

RequestTimeout = "notionhq_client_request_timeout";

325

ResponseError = "notionhq_client_response_error";

326

}

327

328

type NotionErrorCode = APIErrorCode | ClientErrorCode;

329

330

type NotionClientError = APIResponseError | UnknownHTTPResponseError | RequestTimeoutError;

331

332

class APIResponseError extends Error {

333

code: APIErrorCode;

334

status: number;

335

headers: Record<string, string>;

336

body: string;

337

}

338

339

class UnknownHTTPResponseError extends Error {

340

code: ClientErrorCode.ResponseError;

341

status: number;

342

body: string;

343

}

344

345

class RequestTimeoutError extends Error {

346

code: ClientErrorCode.RequestTimeout;

347

}

348

349

function isNotionClientError(error: unknown): error is NotionClientError;

350

```