or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

client.mderrors.mdexchanges.mdindex.mdinternal.mdoperations.mdutilities.md

errors.mddocs/

0

# Error Handling

1

2

Comprehensive error handling system for GraphQL and network errors, providing unified error representation and detailed error information for debugging and user feedback.

3

4

## Capabilities

5

6

### CombinedError Class

7

8

Unified error class that combines GraphQL errors and network errors into a single error instance.

9

10

```typescript { .api }

11

/**

12

* Combined error class for GraphQL and network errors

13

*/

14

class CombinedError extends Error {

15

/** Network-level error (fetch failures, timeouts, etc.) */

16

networkError?: Error;

17

/** Array of GraphQL execution errors */

18

graphQLErrors: GraphQLError[];

19

/** HTTP response that caused the error */

20

response?: Response;

21

22

/**

23

* Create a new CombinedError

24

* @param params - Error parameters

25

*/

26

constructor(params: {

27

networkError?: Error;

28

graphQLErrors?: readonly GraphQLError[];

29

response?: Response;

30

});

31

32

/** Error message combining network and GraphQL errors */

33

message: string;

34

/** Error name */

35

name: string;

36

}

37

```

38

39

**Usage Examples:**

40

41

```typescript

42

import { CombinedError } from "@urql/core";

43

44

// Handle errors from query results

45

const result = await client.query(GetUserQuery, { id: "123" }).toPromise();

46

47

if (result.error) {

48

const error = result.error;

49

50

// Check for network errors

51

if (error.networkError) {

52

console.error("Network error:", error.networkError.message);

53

54

// Handle specific network errors

55

if (error.networkError.message.includes('Failed to fetch')) {

56

showOfflineMessage();

57

}

58

}

59

60

// Check for GraphQL errors

61

if (error.graphQLErrors.length > 0) {

62

error.graphQLErrors.forEach(gqlError => {

63

console.error("GraphQL error:", gqlError.message);

64

65

// Handle specific GraphQL error types

66

if (gqlError.extensions?.code === 'UNAUTHENTICATED') {

67

redirectToLogin();

68

}

69

});

70

}

71

72

// Access HTTP response for status codes

73

if (error.response) {

74

console.log("Response status:", error.response.status);

75

console.log("Response headers:", error.response.headers);

76

}

77

}

78

79

// Create custom combined errors

80

const customError = new CombinedError({

81

networkError: new Error("Connection timeout"),

82

graphQLErrors: [{

83

message: "User not found",

84

locations: [{ line: 2, column: 3 }],

85

path: ["user"],

86

extensions: { code: "USER_NOT_FOUND" }

87

}],

88

});

89

```

90

91

### Error Result Creation

92

93

Create error operation results for custom exchanges and error handling.

94

95

```typescript { .api }

96

/**

97

* Create an error OperationResult from an error

98

* @param operation - The operation that failed

99

* @param error - Error instance (Error or CombinedError)

100

* @param response - Optional ExecutionResult with partial data

101

* @returns OperationResult with error information

102

*/

103

function makeErrorResult<Data = any, Variables extends AnyVariables = AnyVariables>(

104

operation: Operation<Data, Variables>,

105

error: Error | CombinedError,

106

response?: ExecutionResult

107

): OperationResult<Data, Variables>;

108

```

109

110

**Usage Examples:**

111

112

```typescript

113

import { makeErrorResult, CombinedError } from "@urql/core";

114

115

// In a custom exchange

116

const customExchange: Exchange = ({ forward }) => ops$ => {

117

return pipe(

118

ops$,

119

mergeMap(operation => {

120

try {

121

return forward(fromValue(operation));

122

} catch (error) {

123

// Create error result for exceptions

124

return fromValue(makeErrorResult(

125

operation,

126

new CombinedError({

127

networkError: error as Error

128

})

129

));

130

}

131

})

132

);

133

};

134

135

// Handle timeout errors

136

const timeoutExchange: Exchange = ({ forward }) => ops$ => {

137

return pipe(

138

ops$,

139

mergeMap(operation => {

140

const timeout$ = pipe(

141

timer(30000), // 30 second timeout

142

map(() => makeErrorResult(

143

operation,

144

new CombinedError({

145

networkError: new Error("Request timeout")

146

})

147

))

148

);

149

150

return pipe(

151

race([forward(fromValue(operation)), timeout$]),

152

take(1)

153

);

154

})

155

);

156

};

157

```

158

159

### GraphQL Error Types

160

161

Standard GraphQL error interface and extensions.

162

163

```typescript { .api }

164

interface GraphQLError {

165

/** Error message */

166

message: string;

167

/** Source locations where error occurred */

168

locations?: readonly GraphQLErrorLocation[];

169

/** Path to the field that caused the error */

170

path?: readonly (string | number)[];

171

/** Additional error information */

172

extensions?: GraphQLErrorExtensions;

173

}

174

175

interface GraphQLErrorLocation {

176

/** Line number in GraphQL document */

177

line: number;

178

/** Column number in GraphQL document */

179

column: number;

180

}

181

182

interface GraphQLErrorExtensions {

183

/** Error code for programmatic handling */

184

code?: string;

185

/** Additional error metadata */

186

[key: string]: any;

187

}

188

189

type ErrorLike = Partial<GraphQLError> | Error;

190

```

191

192

**Usage Examples:**

193

194

```typescript

195

// Handle different error types

196

result.error?.graphQLErrors.forEach(error => {

197

switch (error.extensions?.code) {

198

case 'UNAUTHENTICATED':

199

// Redirect to login

200

window.location.href = '/login';

201

break;

202

203

case 'FORBIDDEN':

204

// Show access denied message

205

showError("You don't have permission to perform this action");

206

break;

207

208

case 'VALIDATION_ERROR':

209

// Show field validation errors

210

if (error.extensions?.field) {

211

showFieldError(error.extensions.field, error.message);

212

}

213

break;

214

215

default:

216

// Generic error handling

217

showError(error.message);

218

}

219

});

220

```

221

222

### Error Context and Metadata

223

224

Access error context and debugging information.

225

226

```typescript { .api }

227

interface OperationResult<Data = any, Variables extends AnyVariables = AnyVariables> {

228

/** The operation that produced this result */

229

operation: Operation<Data, Variables>;

230

/** Result data (may be partial if errors occurred) */

231

data?: Data;

232

/** Combined error information */

233

error?: CombinedError;

234

/** Additional response metadata */

235

extensions?: Record<string, any>;

236

/** Whether result is stale and will be updated */

237

stale: boolean;

238

/** Whether more results will follow */

239

hasNext: boolean;

240

}

241

```

242

243

**Usage Examples:**

244

245

```typescript

246

// Comprehensive error logging

247

const result = await client.query(GetUserQuery, { id: "123" }).toPromise();

248

249

if (result.error) {

250

// Log full error context

251

console.group(`Error in ${result.operation.kind} operation`);

252

console.log("Operation:", result.operation.query);

253

console.log("Variables:", result.operation.variables);

254

console.log("Error:", result.error.message);

255

256

if (result.error.networkError) {

257

console.log("Network Error:", result.error.networkError);

258

}

259

260

if (result.error.graphQLErrors.length > 0) {

261

console.log("GraphQL Errors:", result.error.graphQLErrors);

262

}

263

264

if (result.error.response) {

265

console.log("Response Status:", result.error.response.status);

266

console.log("Response Headers:", [...result.error.response.headers.entries()]);

267

}

268

269

console.groupEnd();

270

}

271

272

// Handle partial data with errors

273

if (result.data && result.error) {

274

// Some fields succeeded, others failed

275

console.log("Partial data received:", result.data);

276

console.log("Errors for specific fields:", result.error.graphQLErrors);

277

278

// Use partial data but show error indicators

279

displayPartialData(result.data, result.error.graphQLErrors);

280

}

281

```

282

283

### Error Handling Patterns

284

285

Common patterns for handling errors in different scenarios.

286

287

```typescript { .api }

288

// Retry pattern with exponential backoff

289

async function executeWithRetry<T>(

290

operation: () => Promise<OperationResult<T>>,

291

maxRetries = 3

292

): Promise<OperationResult<T>> {

293

let lastError: CombinedError | undefined;

294

295

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

296

try {

297

const result = await operation();

298

299

if (!result.error) {

300

return result;

301

}

302

303

// Don't retry GraphQL errors (they won't change)

304

if (result.error.graphQLErrors.length > 0 && !result.error.networkError) {

305

return result;

306

}

307

308

lastError = result.error;

309

310

if (attempt < maxRetries) {

311

// Exponential backoff

312

await new Promise(resolve =>

313

setTimeout(resolve, Math.pow(2, attempt) * 1000)

314

);

315

}

316

} catch (error) {

317

lastError = error as CombinedError;

318

}

319

}

320

321

throw lastError;

322

}

323

324

// Usage

325

try {

326

const result = await executeWithRetry(() =>

327

client.query(GetUserQuery, { id: "123" }).toPromise()

328

);

329

// Handle successful result

330

} catch (error) {

331

// Handle final error after retries

332

}

333

```

334

335

## Types

336

337

### Error Types

338

339

```typescript { .api }

340

class CombinedError extends Error {

341

networkError?: Error;

342

graphQLErrors: GraphQLError[];

343

response?: Response;

344

345

constructor(params: {

346

networkError?: Error;

347

graphQLErrors?: readonly GraphQLError[];

348

response?: Response;

349

});

350

}

351

352

interface GraphQLError {

353

message: string;

354

locations?: readonly GraphQLErrorLocation[];

355

path?: readonly (string | number)[];

356

extensions?: GraphQLErrorExtensions;

357

}

358

359

interface GraphQLErrorLocation {

360

line: number;

361

column: number;

362

}

363

364

interface GraphQLErrorExtensions {

365

code?: string;

366

[key: string]: any;

367

}

368

369

type ErrorLike = Partial<GraphQLError> | Error;

370

```

371

372

### Response Types

373

374

```typescript { .api }

375

interface ExecutionResult {

376

data?: null | Record<string, any>;

377

errors?: ErrorLike[] | readonly ErrorLike[];

378

extensions?: Record<string, any>;

379

hasNext?: boolean;

380

incremental?: IncrementalPayload[];

381

pending?: readonly PendingIncrementalResult[];

382

}

383

```