Files
motia/bitbylaw/.cursor/architecture/error-handling.mdc
2025-10-19 14:57:07 +00:00

122 lines
2.9 KiB
Plaintext

---
description: How to handle errors in a Motia project
globs:
alwaysApply: true
---
# Error Handling Guide
Errors happen, but we need to handle them gracefully. Make sure you create a custom error class for your project, underneath `/src/errors/` folder.
## Good practices
- Use Custom error to return errors to the client.
- Anything that is not the error class, should be logged with `logger.error`. And root cause should be omitted to the client.
## Create a custom Error class
Name: `/src/errors/base.error.ts`
```typescript
export class BaseError extends Error {
public readonly status: number
public readonly code: string
public readonly metadata: Record<string, any>
constructor(
message: string,
status: number = 500,
code: string = 'INTERNAL_SERVER_ERROR',
metadata: Record<string, any> = {}
) {
super(message)
this.name = this.constructor.name
this.status = status
this.code = code
this.metadata = metadata
// Maintains proper stack trace for where our error was thrown
Error.captureStackTrace(this, this.constructor)
}
toJSON() {
return {
error: {
name: this.name,
message: this.message,
code: this.code,
status: this.status,
...(Object.keys(this.metadata).length > 0 && { metadata: this.metadata }),
},
}
}
}
```
Then create sub class for specific errors that are commonly thrown in your project.
Name: `/src/errors/not-found.error.ts`
```typescript
import { BaseError } from './base.error'
export class NotFoundError extends BaseError {
constructor(message: string = 'Not Found', metadata: Record<string, any> = {}) {
super(message, 404, 'NOT_FOUND', metadata)
}
}
```
## Core Middleware
Make sure you create a core middleware that will be added to ALL API Steps.
File: `/src/middlewares/core.middleware.ts`
```typescript
import { ApiMiddleware } from 'motia'
import { ZodError } from 'zod'
import { BaseError } from '../errors/base.error'
export const coreMiddleware: ApiMiddleware = async (req, ctx, next) => {
const logger = ctx.logger
try {
return await next()
} catch (error: any) {
if (error instanceof ZodError) {
logger.error('Validation error', {
error,
stack: error.stack,
errors: error.errors,
})
return {
status: 400,
body: {
error: 'Invalid request body',
data: error.errors,
},
}
} else if (error instanceof BaseError) {
logger.error('BaseError', {
status: error.status,
code: error.code,
metadata: error.metadata,
name: error.name,
message: error.message,
})
return { status: error.status, body: error.toJSON() }
}
logger.error('Error while performing request', {
error,
body: req.body,
stack: error.stack,
})
return { status: 500, body: { error: 'Internal Server Error' } }
}
}
```