or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

composite.mdconstraints.mdcontracts.mdindex.mdliterals.mdprimitives.mdresults.mdtemplates.mdunion-intersect.mdutilities.mdvalidation.md

results.mddocs/

0

# Results and Errors

1

2

Structured results for validation operations with detailed error information. The result system provides comprehensive feedback about validation success or failure, including specific error codes and contextual information.

3

4

## Capabilities

5

6

### Result Types

7

8

The fundamental result types returned by validation operations.

9

10

```typescript { .api }

11

/**

12

* Result of a validation operation - either success or failure

13

*/

14

type Result<T> = Success<T> | Failure;

15

16

/**

17

* Successful validation result

18

*/

19

interface Success<T> {

20

success: true;

21

value: T;

22

}

23

24

/**

25

* Failed validation result with detailed error information

26

*/

27

interface Failure {

28

success: false;

29

code: Failcode;

30

message: string;

31

expected: Runtype;

32

received: unknown;

33

details?: Record<PropertyKey, Failure>;

34

detail?: Failure;

35

thrown?: unknown;

36

}

37

```

38

39

**Usage Examples:**

40

41

```typescript

42

import { String, Number, Object } from "runtypes";

43

44

// Inspect method returns Result<T>

45

const stringResult = String.inspect("hello");

46

if (stringResult.success) {

47

console.log("Value:", stringResult.value); // "hello"

48

} else {

49

console.log("Error:", stringResult.message);

50

}

51

52

// Failed validation

53

const numberResult = Number.inspect("not a number");

54

if (!numberResult.success) {

55

console.log("Code:", numberResult.code); // "TYPE_INCORRECT"

56

console.log("Expected:", numberResult.expected.tag); // "number"

57

console.log("Received:", numberResult.received); // "not a number"

58

}

59

```

60

61

### Failure Codes

62

63

Predefined error codes that categorize different types of validation failures.

64

65

```typescript { .api }

66

/**

67

* Predefined error codes for validation failures

68

*/

69

type Failcode =

70

| "TYPE_INCORRECT" // Wrong primitive type (string vs number)

71

| "VALUE_INCORRECT" // Wrong value (42 vs 43 for Literal(42))

72

| "KEY_INCORRECT" // Invalid object key in Record

73

| "CONTENT_INCORRECT" // Invalid array/object contents

74

| "ARGUMENTS_INCORRECT" // Invalid function arguments

75

| "RETURN_INCORRECT" // Invalid function return value

76

| "RESOLVE_INCORRECT" // Invalid Promise resolution value

77

| "CONSTRAINT_FAILED" // Custom constraint not satisfied

78

| "PROPERTY_MISSING" // Required object property missing

79

| "PROPERTY_PRESENT" // Unexpected property in exact object

80

| "NOTHING_EXPECTED" // Value provided but none expected

81

| "PARSING_FAILED" // Parser function threw error

82

| "INSTANCEOF_FAILED"; // instanceof check failed

83

```

84

85

**Usage Examples:**

86

87

```typescript

88

import { String, Number, Object, Array, Literal, Union } from "runtypes";

89

90

// TYPE_INCORRECT - wrong primitive type

91

const typeError = String.inspect(123);

92

// { success: false, code: "TYPE_INCORRECT", message: "Expected string, but was number", ... }

93

94

// VALUE_INCORRECT - wrong literal value

95

const valueError = Literal("hello").inspect("world");

96

// { success: false, code: "VALUE_INCORRECT", message: "Expected \"hello\", but was \"world\"", ... }

97

98

// CONTENT_INCORRECT - array/object content errors

99

const User = Object({ name: String, age: Number });

100

const contentError = User.inspect({ name: "Alice", age: "not a number" });

101

// { success: false, code: "CONTENT_INCORRECT", details: { age: Failure }, ... }

102

103

// PROPERTY_MISSING - required property missing

104

const missingError = User.inspect({ name: "Alice" });

105

// { success: false, code: "CONTENT_INCORRECT", details: { age: { code: "PROPERTY_MISSING", ... } }, ... }

106

107

// CONSTRAINT_FAILED - custom constraint

108

const PositiveNumber = Number.withConstraint(n => n > 0 || "Must be positive");

109

const constraintError = PositiveNumber.inspect(-5);

110

// { success: false, code: "CONSTRAINT_FAILED", thrown: "Must be positive", ... }

111

```

112

113

### ValidationError

114

115

Exception thrown by validation methods when validation fails.

116

117

```typescript { .api }

118

/**

119

* Error thrown when validation fails

120

*/

121

class ValidationError extends Error {

122

name: "ValidationError";

123

message: string;

124

failure: Failure;

125

126

constructor(failure: Failure);

127

128

static isValidationError(value: unknown): value is ValidationError;

129

}

130

```

131

132

**Usage Examples:**

133

134

```typescript

135

import { String, ValidationError } from "runtypes";

136

137

// Catching validation errors

138

try {

139

const result = String.check(123);

140

} catch (error) {

141

if (ValidationError.isValidationError(error)) {

142

console.log("Validation failed:", error.message);

143

console.log("Error code:", error.failure.code);

144

console.log("Expected:", error.failure.expected.tag);

145

console.log("Received:", error.failure.received);

146

}

147

}

148

149

// Custom error handling

150

function safeValidate<T>(runtype: Runtype<T>, value: unknown): T | null {

151

try {

152

return runtype.check(value);

153

} catch (error) {

154

if (ValidationError.isValidationError(error)) {

155

console.warn(`Validation failed: ${error.message}`);

156

return null;

157

}

158

throw error; // Re-throw non-validation errors

159

}

160

}

161

162

const result = safeValidate(String, 123); // null, with warning logged

163

```

164

165

## Complex Error Structures

166

167

### Nested Object Errors

168

169

```typescript

170

import { Object, String, Number, Array } from "runtypes";

171

172

const User = Object({

173

profile: Object({

174

name: String,

175

age: Number,

176

contact: Object({

177

email: String,

178

phone: String

179

})

180

}),

181

preferences: Object({

182

theme: Union(Literal("light"), Literal("dark")),

183

notifications: Boolean

184

})

185

});

186

187

// Validate complex nested structure

188

const result = User.inspect({

189

profile: {

190

name: "Alice",

191

age: "not a number", // Error here

192

contact: {

193

email: "alice@example.com",

194

phone: 1234567890 // Error here - should be string

195

}

196

},

197

preferences: {

198

theme: "invalid", // Error here

199

notifications: true

200

}

201

});

202

203

if (!result.success) {

204

console.log("Main error:", result.code); // "CONTENT_INCORRECT"

205

206

// Navigate nested errors

207

const profileErrors = result.details?.profile;

208

if (profileErrors && !profileErrors.success) {

209

const ageError = profileErrors.details?.age;

210

const contactErrors = profileErrors.details?.contact;

211

212

if (ageError && !ageError.success) {

213

console.log("Age error:", ageError.code); // "TYPE_INCORRECT"

214

}

215

216

if (contactErrors && !contactErrors.success) {

217

const phoneError = contactErrors.details?.phone;

218

if (phoneError && !phoneError.success) {

219

console.log("Phone error:", phoneError.code); // "TYPE_INCORRECT"

220

}

221

}

222

}

223

}

224

```

225

226

### Array Validation Errors

227

228

```typescript

229

import { Array, Object, String, Number } from "runtypes";

230

231

const Users = Array(Object({

232

id: Number,

233

name: String,

234

email: String

235

}));

236

237

const result = Users.inspect([

238

{ id: 1, name: "Alice", email: "alice@example.com" }, // Valid

239

{ id: "2", name: "Bob", email: "bob@example.com" }, // Invalid id

240

{ id: 3, name: "Charlie" }, // Missing email

241

{ id: 4, name: "David", email: "david@example.com" } // Valid

242

]);

243

244

if (!result.success) {

245

console.log("Array validation failed");

246

247

// Check individual element errors

248

Object.entries(result.details || {}).forEach(([index, error]) => {

249

console.log(`Element ${index} errors:`);

250

if (!error.success && error.details) {

251

Object.entries(error.details).forEach(([field, fieldError]) => {

252

if (!fieldError.success) {

253

console.log(` ${field}: ${fieldError.message}`);

254

}

255

});

256

}

257

});

258

}

259

```

260

261

### Union Validation Errors

262

263

```typescript

264

import { Union, String, Number, Object, Literal } from "runtypes";

265

266

const ID = Union(String, Number);

267

const Status = Union(Literal("active"), Literal("inactive"), Literal("pending"));

268

269

// Union errors show all attempted alternatives

270

const idResult = ID.inspect(true);

271

if (!idResult.success) {

272

console.log("Union validation failed:", idResult.code); // "TYPE_INCORRECT"

273

console.log("Details:", idResult.details);

274

// Details will contain failure information for each alternative:

275

// { 0: Failure (String attempt), 1: Failure (Number attempt) }

276

}

277

278

const statusResult = Status.inspect("unknown");

279

if (!statusResult.success) {

280

console.log("Status validation failed");

281

// Shows failures for each literal alternative

282

}

283

```

284

285

## Error Analysis and Debugging

286

287

### Custom Error Formatters

288

289

```typescript

290

import { ValidationError, type Failure } from "runtypes";

291

292

function formatValidationError(failure: Failure, path: string = ""): string {

293

const location = path ? `at ${path}: ` : "";

294

295

switch (failure.code) {

296

case "TYPE_INCORRECT":

297

return `${location}Expected ${failure.expected.tag} but received ${typeof failure.received}`;

298

299

case "VALUE_INCORRECT":

300

return `${location}Expected specific value but received ${JSON.stringify(failure.received)}`;

301

302

case "PROPERTY_MISSING":

303

return `${location}Required property is missing`;

304

305

case "PROPERTY_PRESENT":

306

return `${location}Unexpected property ${JSON.stringify(failure.received)}`;

307

308

case "CONTENT_INCORRECT":

309

if (failure.details) {

310

const errors = Object.entries(failure.details)

311

.map(([key, detail]) => formatValidationError(detail, `${path}${path ? '.' : ''}${key}`))

312

.join('\n');

313

return `${location}Content validation failed:\n${errors}`;

314

}

315

return `${location}Content validation failed`;

316

317

case "CONSTRAINT_FAILED":

318

return `${location}Constraint failed: ${failure.thrown}`;

319

320

default:

321

return `${location}Validation failed: ${failure.message}`;

322

}

323

}

324

325

// Usage

326

try {

327

const user = User.check(invalidData);

328

} catch (error) {

329

if (ValidationError.isValidationError(error)) {

330

console.log(formatValidationError(error.failure));

331

}

332

}

333

```

334

335

### Error Collection and Reporting

336

337

```typescript

338

import { type Failure } from "runtypes";

339

340

interface ValidationReport {

341

isValid: boolean;

342

errors: Array<{

343

path: string;

344

code: string;

345

message: string;

346

expected: string;

347

received: unknown;

348

}>;

349

}

350

351

function collectErrors(failure: Failure, path: string = ""): ValidationReport["errors"] {

352

const errors: ValidationReport["errors"] = [];

353

354

if (failure.code === "CONTENT_INCORRECT" && failure.details) {

355

// Collect nested errors

356

for (const [key, detail] of Object.entries(failure.details)) {

357

const nestedPath = path ? `${path}.${key}` : key;

358

errors.push(...collectErrors(detail, nestedPath));

359

}

360

} else {

361

// Leaf error

362

errors.push({

363

path,

364

code: failure.code,

365

message: failure.message,

366

expected: failure.expected.tag,

367

received: failure.received

368

});

369

}

370

371

return errors;

372

}

373

374

function validateWithReport<T>(runtype: Runtype<T>, value: unknown): ValidationReport {

375

const result = runtype.inspect(value);

376

377

if (result.success) {

378

return { isValid: true, errors: [] };

379

}

380

381

return {

382

isValid: false,

383

errors: collectErrors(result)

384

};

385

}

386

387

// Usage

388

const report = validateWithReport(User, userData);

389

if (!report.isValid) {

390

console.log("Validation errors:");

391

report.errors.forEach(error => {

392

console.log(`- ${error.path}: ${error.message}`);

393

});

394

}

395

```

396

397

### Development vs Production Error Handling

398

399

```typescript

400

import { ValidationError } from "runtypes";

401

402

class AppError extends Error {

403

constructor(

404

message: string,

405

public code: string,

406

public statusCode: number = 400,

407

public details?: any

408

) {

409

super(message);

410

this.name = "AppError";

411

}

412

}

413

414

function handleValidationError(error: ValidationError): AppError {

415

if (process.env.NODE_ENV === 'development') {

416

// Detailed errors in development

417

return new AppError(

418

`Validation failed: ${error.message}`,

419

'VALIDATION_ERROR',

420

400,

421

{

422

code: error.failure.code,

423

expected: error.failure.expected.tag,

424

received: error.failure.received,

425

path: error.failure.details ? Object.keys(error.failure.details) : undefined

426

}

427

);

428

} else {

429

// Generic errors in production

430

return new AppError(

431

"Invalid request data",

432

'VALIDATION_ERROR',

433

400

434

);

435

}

436

}

437

438

// Usage in API handlers

439

function createUser(requestData: unknown) {

440

try {

441

const userData = UserSchema.check(requestData);

442

// Process valid user data...

443

return userData;

444

} catch (error) {

445

if (ValidationError.isValidationError(error)) {

446

throw handleValidationError(error);

447

}

448

throw error;

449

}

450

}

451

```