Files
suplement/.agents/skills/building-with-medusa/reference/error-handling.md
2026-03-07 11:07:45 -03:00

254 lines
5.3 KiB
Markdown

# Error Handling in Medusa
Medusa provides the `MedusaError` class for consistent error responses across your API routes and custom code.
## Contents
- [Using MedusaError](#using-medusaerror)
- [Error Types](#error-types)
- [Error Response Format](#error-response-format)
- [Best Practices](#best-practices)
## Using MedusaError
Use `MedusaError` in API routes, workflows, and custom modules to throw errors that Medusa will automatically format and return to clients:
```typescript
import { MedusaError } from "@medusajs/framework/utils"
// Throw an error
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
"Product not found"
)
```
## Error Types
### NOT_FOUND
Use when a requested resource doesn't exist:
```typescript
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
"Product with ID 'prod_123' not found"
)
```
**HTTP Status**: 404
### INVALID_DATA
Use when request data fails validation or is malformed:
```typescript
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
"Email address is invalid"
)
```
**HTTP Status**: 400
### UNAUTHORIZED
Use when authentication is required but not provided:
```typescript
throw new MedusaError(
MedusaError.Types.UNAUTHORIZED,
"Authentication required to access this resource"
)
```
**HTTP Status**: 401
### NOT_ALLOWED
Use when the user is authenticated but doesn't have permission:
```typescript
throw new MedusaError(
MedusaError.Types.NOT_ALLOWED,
"You don't have permission to delete this product"
)
```
**HTTP Status**: 403
### CONFLICT
Use when the operation conflicts with existing data:
```typescript
throw new MedusaError(
MedusaError.Types.CONFLICT,
"A product with this handle already exists"
)
```
**HTTP Status**: 409
### DUPLICATE_ERROR
Use when trying to create a duplicate resource:
```typescript
throw new MedusaError(
MedusaError.Types.DUPLICATE_ERROR,
"Email address is already registered"
)
```
**HTTP Status**: 422
### INVALID_STATE
Use when the resource is in an invalid state for the operation:
```typescript
throw new MedusaError(
MedusaError.Types.INVALID_STATE,
"Cannot cancel an order that has already been fulfilled"
)
```
**HTTP Status**: 400
## Error Response Format
Medusa automatically formats errors into a consistent JSON response:
```json
{
"type": "not_found",
"message": "Product with ID 'prod_123' not found"
}
```
## Best Practices
### 1. Use Specific Error Types
Choose the most appropriate error type for the situation:
```typescript
// ✅ GOOD: Uses specific error types
export async function GET(req: MedusaRequest, res: MedusaResponse) {
const { id } = req.params
const query = req.scope.resolve("query")
const { data } = await query.graph({
entity: "product",
fields: ["id", "title"],
filters: { id },
})
if (!data || data.length === 0) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
`Product with ID '${id}' not found`
)
}
return res.json({ product: data[0] })
}
// ❌ BAD: Uses generic error
export async function GET(req: MedusaRequest, res: MedusaResponse) {
const { id } = req.params
const query = req.scope.resolve("query")
const { data } = await query.graph({
entity: "product",
fields: ["id", "title"],
filters: { id },
})
if (!data || data.length === 0) {
throw new Error("Product not found") // Generic error
}
return res.json({ product: data[0] })
}
```
### 2. Provide Clear Error Messages
Error messages should be descriptive and help users understand what went wrong:
```typescript
// ✅ GOOD: Clear, specific message
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
"Cannot create product: title must be at least 3 characters long"
)
// ❌ BAD: Vague message
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
"Invalid input"
)
```
### 3. Include Context in Error Messages
```typescript
// ✅ GOOD: Includes relevant context
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
`Product with ID '${productId}' not found`
)
// ✅ GOOD: Includes field name
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Invalid email format: '${email}'`
)
```
### 4. Handle Workflow Errors
When calling workflows from API routes, catch and transform errors:
```typescript
// ✅ GOOD: Catches and transforms workflow errors
export async function POST(req: MedusaRequest, res: MedusaResponse) {
const { data } = req.validatedBody
try {
const { result } = await myWorkflow(req.scope).run({
input: { data },
})
return res.json({ result })
} catch (error) {
// Transform workflow errors into API errors
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Failed to create resource: ${error.message}`
)
}
}
```
### 5. Use Validation Middleware
Let validation middleware handle input validation errors:
```typescript
// ✅ GOOD: Middleware handles validation
// middlewares.ts
const MySchema = z.object({
email: z.string().email("Invalid email address"),
age: z.number().min(18, "Must be at least 18 years old"),
})
export const myMiddlewares: MiddlewareRoute[] = [
{
matcher: "/store/my-route",
method: "POST",
middlewares: [validateAndTransformBody(MySchema)],
},
]
// route.ts - No need to validate again
export async function POST(req: MedusaRequest, res: MedusaResponse) {
const { email, age } = req.validatedBody // Already validated
// Your logic here
}
```