12 KiB
Top Errors and Solutions
Complete troubleshooting guide for all documented Cloudflare Images errors.
Direct Creator Upload Errors
1. CORS Error - Content-Type Not Allowed
Error:
Access to XMLHttpRequest blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers
Source: Cloudflare Community #345739, #368114
Why It Happens:
Server CORS settings only allow multipart/form-data for Content-Type header.
Solution:
// ✅ CORRECT
const formData = new FormData();
formData.append('file', fileInput.files[0]);
await fetch(uploadURL, {
method: 'POST',
body: formData // Browser sets multipart/form-data automatically
});
// ❌ WRONG
await fetch(uploadURL, {
headers: { 'Content-Type': 'application/json' }, // CORS error
body: JSON.stringify({ file: base64Image })
});
Prevention:
- Use FormData API
- Let browser set Content-Type header (don't set manually)
- Name field
file(notimageor other)
2. Error 5408 - Upload Timeout
Error: Error 5408 after ~15 seconds
Source: Cloudflare Community #571336
Why It Happens: Cloudflare has 30-second request timeout. Slow uploads or large files exceed limit.
Solution:
const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
if (file.size > MAX_FILE_SIZE) {
alert('File too large. Please select an image under 10MB.');
return;
}
// Compress image before upload (optional)
async function compressImage(file) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const img = await createImageBitmap(file);
const maxWidth = 4000;
const scale = Math.min(1, maxWidth / img.width);
canvas.width = img.width * scale;
canvas.height = img.height * scale;
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
return new Promise((resolve) => {
canvas.toBlob((blob) => resolve(blob), 'image/jpeg', 0.9);
});
}
Prevention:
- Limit file size (10MB max recommended)
- Compress images client-side if needed
- Show upload progress to user
- Handle timeout errors gracefully
3. Error 400 - Invalid File Parameter
Error: 400 Bad Request with unhelpful message
Source: Cloudflare Community #487629
Why It Happens:
File field must be named file (not image, photo, etc.).
Solution:
// ✅ CORRECT
formData.append('file', imageFile);
// ❌ WRONG
formData.append('image', imageFile); // 400 error
formData.append('photo', imageFile); // 400 error
formData.append('upload', imageFile); // 400 error
Prevention:
- Always name the field
file - Check FormData contents before sending
4. CORS Preflight Failures
Error: Preflight OPTIONS request blocked
Source: Cloudflare Community #306805
Why It Happens:
Calling /direct_upload API directly from browser (should be backend-only).
Solution:
CORRECT ARCHITECTURE:
Browser → POST /api/upload-url → Backend
↓
POST /direct_upload → Cloudflare API
↓
Backend ← Returns uploadURL ← Cloudflare API
↓
Browser receives uploadURL
↓
Browser → Uploads to uploadURL → Cloudflare (direct upload)
Prevention:
- Never expose API token to browser
- Generate upload URL on backend
- Return uploadURL to frontend
- Frontend uploads to uploadURL (not /direct_upload)
Image Transformation Errors
5. Error 9401 - Invalid Arguments
Error: Cf-Resized: err=9401 in response headers
Source: Cloudflare Docs - Troubleshooting
Why It Happens:
Missing required cf.image parameters or invalid values.
Solution:
// ✅ CORRECT
fetch(imageURL, {
cf: {
image: {
width: 800,
quality: 85,
format: 'auto'
}
}
});
// ❌ WRONG
fetch(imageURL, {
cf: {
image: {
width: 'large', // Must be number
quality: 150, // Max 100
format: 'invalid' // Must be valid format
}
}
});
Prevention:
- Validate all parameters
- Use TypeScript for type checking
- Check official docs for valid ranges
6. Error 9402 - Image Too Large
Error: Cf-Resized: err=9402
Source: Cloudflare Docs - Troubleshooting
Why It Happens: Image exceeds maximum area or download fails.
Solution:
// Check image dimensions before transforming
const response = await fetch(imageURL, { method: 'HEAD' });
// Or fetch and check after
const img = await fetch(imageURL);
// Validate size
Prevention:
- Validate source image dimensions
- Max 100 megapixels (e.g., 10000x10000px)
- Use reasonable source images
7. Error 9403 - Request Loop
Error: Cf-Resized: err=9403
Source: Cloudflare Docs - Troubleshooting
Why It Happens: Worker fetching its own URL or already-resized image.
Solution:
// ✅ CORRECT - Fetch external origin
export default {
async fetch(request: Request): Promise<Response> {
const url = new URL(request.url);
if (url.pathname.startsWith('/images/')) {
const imagePath = url.pathname.replace('/images/', '');
const originURL = `https://storage.example.com/${imagePath}`;
return fetch(originURL, {
cf: { image: { width: 800 } }
});
}
return new Response('Not found', { status: 404 });
}
};
// ❌ WRONG - Fetches worker's own URL (loop)
export default {
async fetch(request: Request): Promise<Response> {
return fetch(request, { // Fetches self
cf: { image: { width: 800 } }
});
}
};
Prevention:
- Always fetch external origin
- Don't transform already-transformed images
- Check URL routing logic
8. Error 9406/9419 - Invalid URL Format
Error: Cf-Resized: err=9406 or err=9419
Source: Cloudflare Docs - Troubleshooting
Why It Happens: Image URL uses HTTP (not HTTPS) or contains spaces/unescaped Unicode.
Solution:
// ✅ CORRECT
const filename = "photo name.jpg";
const imageURL = `https://example.com/images/${encodeURIComponent(filename)}`;
// ❌ WRONG
const imageURL = "http://example.com/image.jpg"; // HTTP not allowed
const imageURL = "https://example.com/photo name.jpg"; // Space not encoded
Prevention:
- Always use HTTPS (HTTP not supported)
- URL-encode all paths with
encodeURIComponent() - No spaces or unescaped Unicode in URLs
9. Error 9412 - Non-Image Response
Error: Cf-Resized: err=9412
Source: Cloudflare Docs - Troubleshooting
Why It Happens: Origin server returns HTML (e.g., 404 page) instead of image.
Solution:
// Verify URL before transforming
const originResponse = await fetch(imageURL, { method: 'HEAD' });
const contentType = originResponse.headers.get('content-type');
if (!contentType?.startsWith('image/')) {
return new Response('Not an image', { status: 400 });
}
return fetch(imageURL, {
cf: { image: { width: 800 } }
});
Prevention:
- Verify origin returns image (check Content-Type)
- Handle 404s before transforming
- Validate image URLs
10. Error 9413 - Max Image Area Exceeded
Error: Cf-Resized: err=9413
Source: Cloudflare Docs - Troubleshooting
Why It Happens: Source image exceeds 100 megapixels (e.g., 10000x10000px).
Solution:
const MAX_MEGAPIXELS = 100;
if (width * height > MAX_MEGAPIXELS * 1_000_000) {
return new Response('Image too large', { status: 413 });
}
Prevention:
- Validate image dimensions before transforming
- Pre-process oversized images
- Reject images above threshold (100 megapixels)
Configuration Errors
11. Flexible Variants + Signed URLs Incompatibility
Error: Flexible variants don't work with private images
Source: Cloudflare Docs - Enable flexible variants
Why It Happens:
Flexible variants cannot be used with requireSignedURLs=true.
Solution:
// ✅ CORRECT - Use named variants for private images
await uploadImage({
file: imageFile,
requireSignedURLs: true // Use named variants: /public, /avatar, etc.
});
// ❌ WRONG - Flexible variants don't support signed URLs
// Cannot use: /w=400,sharpen=3 with requireSignedURLs=true
Prevention:
- Use named variants for private images
- Use flexible variants for public images only
12. SVG Resizing Limitation
Error: SVG files don't resize via transformations
Source: Cloudflare Docs - SVG files
Why It Happens: SVG is vector format (inherently scalable), resizing not applicable.
Solution:
// SVGs can be served but not resized
// Use any variant name as placeholder
// https://imagedelivery.net/<HASH>/<SVG_ID>/public
// SVG will be served at original size regardless of variant settings
Prevention:
- Don't try to resize SVGs
- Serve SVGs as-is
- Use variants as placeholders
13. EXIF Metadata Stripped by Default
Error: GPS data, camera settings removed from uploaded JPEGs
Source: Cloudflare Docs - Transform via URL
Why It Happens: Default behavior strips all metadata except copyright.
Solution:
// Preserve metadata
fetch(imageURL, {
cf: {
image: {
width: 800,
metadata: 'keep' // Options: 'none', 'copyright', 'keep'
}
}
});
Prevention:
- Use
metadata=keepif preservation needed - Default
copyrightfor JPEG - Color profiles and EXIF rotation always applied
General Troubleshooting
Images not transforming
Symptoms: /cdn-cgi/image/... returns original or 404
Solutions:
- Enable transformations: Dashboard → Images → Transformations → Enable
- Verify zone proxied (orange cloud)
- Check source image accessible
- Wait 5-10 minutes for propagation
Signed URLs returning 403
Symptoms: 403 Forbidden with signed URL
Solutions:
- Verify image uploaded with
requireSignedURLs=true - Check signature generation (HMAC-SHA256)
- Ensure expiry in future
- Verify signing key matches dashboard
- Cannot use flexible variants (use named variants)
Checking for Errors
Response Headers:
const response = await fetch(transformedImageURL);
const cfResized = response.headers.get('Cf-Resized');
if (cfResized?.includes('err=')) {
console.error('Transformation error:', cfResized);
}
Common patterns:
Cf-Resized: err=9401- Invalid argumentsCf-Resized: err=9403- Request loopCf-Resized: err=9412- Non-image response
Official Documentation
- Troubleshooting: https://developers.cloudflare.com/images/reference/troubleshooting/
- Transform via Workers: https://developers.cloudflare.com/images/transform-images/transform-via-workers/