# Gotchas & Best Practices

## Fit Modes

| Mode         | Best For                | Behavior                              |
| ------------ | ----------------------- | ------------------------------------- |
| `cover`      | Hero images, thumbnails | Fills space, crops excess             |
| `contain`    | Product images, artwork | Preserves full image, may add padding |
| `scale-down` | User uploads            | Never enlarges                        |
| `crop`       | Precise crops           | Uses gravity                          |
| `pad`        | Fixed aspect ratio      | Adds background                       |

## Format Selection

```typescript
format: 'auto' // Recommended - negotiates best format
```

**Support:** AVIF (Chrome 85+, Firefox 93+, Safari 16.4+), WebP (Chrome 23+, Firefox 65+, Safari 14+)

## Quality Settings

| Use Case     | Quality      |
| ------------ | ------------ |
| Thumbnails   | 75-80        |
| Standard     | 85 (default) |
| High-quality | 90-95        |

## Common Errors

### 5403: "Image transformation failed"

- Verify `width`/`height` ≤ 12000
- Check `quality` 1-100, `dpr` 1-3
- Don't combine incompatible options

### 9413: "Rate limit exceeded"

Implement caching and exponential backoff:

```typescript
for (let i = 0; i < 3; i++) {
  try { return await env.IMAGES.input(buffer).transform({...}).output(); }
  catch { await new Promise(r => setTimeout(r, 2 ** i * 1000)); }
}
```

### 5401: "Image too large"

Pre-process images before upload (max 100MB, 12000×12000px)

### 5400: "Invalid image format"

Supported: JPEG, PNG, GIF, WebP, AVIF, SVG

### 401/403: "Unauthorized"

Verify API token has `Cloudflare Images → Edit` permission

## Limits

| Resource       | Limit         |
| -------------- | ------------- |
| Max input size | 100MB         |
| Max dimensions | 12000×12000px |
| Quality range  | 1-100         |
| DPR range      | 1-3           |
| API rate limit | ~1200 req/min |

## AVIF Gotchas

- **Slower encoding**: First request may have higher latency
- **Browser detection**:

```typescript
const format = /image\/avif/.test(request.headers.get('Accept') || '') ? 'avif' : 'webp'
```

## Anti-Patterns

```typescript
// ❌ No caching - transforms every request
return env.IMAGES.input(buffer).transform({...}).output().response();

// ❌ cover without both dimensions
transform({ width: 800, fit: 'cover' })

// ✅ Always set both for cover
transform({ width: 800, height: 600, fit: 'cover' })

// ❌ Exposes API token to client
// ✅ Use Direct Creator Upload (patterns.md)
```

## Debugging

```typescript
// Check response headers
console.log('Content-Type:', response.headers.get('Content-Type'))

// Test with curl
// curl -I "https://imagedelivery.net/{hash}/{id}/width=800,format=avif"

// Monitor logs
// npx wrangler tail
```
