-
Notifications
You must be signed in to change notification settings - Fork 11
Troubleshooting
Common issues and their solutions when deploying and using R2-Manager-Worker.
Symptoms:
- Cannot access the application
- Redirected to login repeatedly
- 401 Unauthorized errors in console
Solutions:
-
Verify TEAM_DOMAIN includes full URL:
npx wrangler secret put TEAM_DOMAIN # Enter: https://yourteam.cloudflareaccess.com -
Confirm POLICY_AUD matches Application Audience Tag:
- Go to Zero Trust → Access → Applications → Select your app
- Copy Application Audience (AUD) Tag from Overview tab
- Set secret:
npx wrangler secret put POLICY_AUD
-
Check GitHub account is allowed:
- Go to Zero Trust → Access → Applications → Select your app
- Review Policies tab
- Ensure your GitHub account matches the Allow policy
-
Clear browser cookies:
- Open DevTools (F12) → Application tab → Cookies
- Delete all cookies for your domain
- Try logging in again
-
Verify JWT cookie is set:
- After logging in, check DevTools → Application → Cookies
- Look for
cf-access-jwt-assertioncookie - If missing, check Cloudflare Access configuration
Symptoms:
- Cannot list files in bucket
- Error message: "Failed to list files"
- 404 errors in Worker logs
Solutions:
-
Verify bucket exists:
npx wrangler r2 bucket list
-
Check bucket name in wrangler.toml:
[[r2_buckets]] binding = "BUCKET" bucket_name = "exact-bucket-name" # Must match exactly (case-sensitive)
-
Verify ACCOUNT_ID is correct:
- Go to Cloudflare Dashboard
- Find Account ID in right sidebar
- Update secret:
npx wrangler secret put ACCOUNT_ID
-
Check API token permissions:
- Go to API Tokens page
- Verify token has Workers R2 Storage → Edit permission
- If missing, create new token with correct permissions
- Update secret:
npx wrangler secret put API_KEY
Symptoms:
- "Failed to create bucket" error
- Error about invalid bucket name
Solutions:
-
Verify bucket name meets requirements:
- Only lowercase letters (a-z), numbers (0-9), and hyphens (-)
- Cannot begin or end with a hyphen
- Must be 3-63 characters in length
- Examples:
- ✅
my-bucket-123 - ✅
data-storage - ❌
My-Bucket(uppercase) - ❌
-invalid(starts with hyphen) - ❌
ab(too short)
- ✅
-
Check if bucket name already exists:
npx wrangler r2 bucket list
Symptoms:
-
wrangler deploycommand fails - Authentication errors during deploy
- Build errors
Solutions:
-
Re-authenticate with Cloudflare:
npx wrangler login
-
Verify secrets are set:
npx wrangler secret list
Should show:
- ACCOUNT_ID
- CF_EMAIL
- API_KEY
- TEAM_DOMAIN
- POLICY_AUD
-
Check build succeeds:
npm run build
If build fails, fix any TypeScript or linting errors.
-
Verify wrangler.toml syntax:
- Check for typos in configuration
- Ensure multiline arrays use proper TOML syntax
- Validate binding names match environment
-
Check API token permissions: Token needs:
- Account → Workers Scripts → Edit
- Account → Workers R2 Storage → Edit
- Zone → Workers Routes → Edit (if using custom domain)
Symptoms:
- Blank page after deployment
- 404 errors for JavaScript/CSS files
- "Failed to fetch" errors in console
Solutions:
-
Verify build was successful:
npm run build
Check that
dist/folder contains:index.html-
assets/folder with JS and CSS files - Favicon and image files
-
Check ASSETS binding in wrangler.toml:
# Should be present (automatically configured by Wrangler) # No manual configuration needed for assets
-
Redeploy with fresh build:
rm -rf dist npm run build npx wrangler deploy
Symptoms:
- "CORS policy" error messages
- API requests blocked by browser
- Preflight OPTIONS requests failing
Solutions:
-
Verify Cloudflare Access domain matches Worker domain:
- Access application domain should match deployed Worker domain
- Both should use same subdomain/domain
-
Create Bypass policy for static assets:
- Go to Zero Trust → Access → Applications → Select your app
- Add Bypass policy for:
/site.webmanifest/favicon.ico/logo.png- Other static assets
-
Check API requests include credentials:
In
src/services/api.ts:const response = await fetch(url, { ...options, credentials: "include", // Must be present });
-
Verify Worker CORS headers:
Headers should include:
'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, DELETE, OPTIONS, PATCH', 'Access-Control-Allow-Headers': 'Content-Type, Authorization, ...'
Symptoms:
- Upload progress bar reaches 100% but fails
- "Upload failed" error
- Worker returns 413 or 500 error
Solutions:
-
Check your Cloudflare plan limits:
- Free/Pro Plans: 100MB maximum
- Business Plan: 200MB maximum
- Enterprise Plan: 500MB maximum
-
Upgrade plan if needed:
- Go to Cloudflare Dashboard
- Navigate to Plans section
- Upgrade to Business or Enterprise for larger uploads
-
Use chunked uploads:
- Application automatically chunks files >10MB
- Ensure chunking logic in
src/services/api.tsis working - Check Worker receives correct chunk headers
-
Verify Worker can handle chunk assembly:
- Check Worker logs for chunk processing
- Ensure all chunks are received before final upload
Symptoms:
- Upload completes successfully
- File not shown in file list
- Need to refresh page to see file
Solutions:
-
Force cache refresh:
- Click refresh icon in UI
- Or add
?skipCache=trueto list request
-
Check file isn't filtered:
- Worker filters out
assets/folder - Ensure file name doesn't match filter criteria
- Worker filters out
-
Verify file list pagination:
- File might be on a different page
- Check pagination cursor is correct
Symptoms:
- Bucket rename takes very long
- Force delete hangs
- Timeout errors
Solutions:
-
For large buckets, be patient:
- Bucket operations iterate through all objects
- Rate limiting delays are built-in (500ms between batches)
- 1000 objects ≈ 5-10 minutes
-
Check Worker logs:
npx wrangler tail
Look for progress messages showing object processing
-
For stuck operations:
- Check if Worker is still running
- View logs in dashboard: Workers & Pages → Select Worker → Logs
- May need to wait for timeout and retry
Symptoms:
- Cannot start Vite dev server
- Cannot start Wrangler dev
- EADDRINUSE error
Solutions:
-
Kill processes using ports:
npx kill-port 5173 # Vite npx kill-port 8787 # Wrangler
-
Or manually find and kill:
# On macOS/Linux lsof -ti:5173 | xargs kill -9 lsof -ti:8787 | xargs kill -9 # On Windows netstat -ano | findstr :5173 taskkill /PID <PID> /F
Symptoms:
- Import errors in console
- TypeScript errors about missing modules
- Build fails with module errors
Solutions:
-
Clear and reinstall node_modules:
rm -rf node_modules package-lock.json npm install
-
Clear Vite cache:
rm -rf node_modules/.vite npm run dev
-
Verify Node.js version:
node --version # Should be 18+
This is expected behavior!
- JWT validation is disabled on localhost
- All API endpoints are accessible without tokens
- This is intentional for easier development
To test with authentication:
- Deploy to production and test there, OR
- Set
.envto use deployed Worker URL:VITE_WORKER_API=https://your-worker.workers.dev
Symptoms:
- 401 errors despite being logged in
- "JWT validation failed" in Worker logs
- Token appears in cookies but still unauthorized
Solutions:
-
Verify token in jwt.io:
- Copy
cf-access-jwt-assertioncookie value from DevTools - Paste into jwt.io
- Check:
-
issmatches your team domain -
audcontains your Application Audience Tag -
exphasn't passed (token not expired)
-
- Copy
-
Check TEAM_DOMAIN format:
# Must include https:// and full domain npx wrangler secret put TEAM_DOMAIN # Enter: https://yourteam.cloudflareaccess.com
-
Verify POLICY_AUD:
npx wrangler secret put POLICY_AUD # Enter: Application Audience Tag from Access dashboard -
Enable debug logging:
Add to
worker/index.ts:console.log("[JWT Debug]", { tokenPresent: !!token, issuer: env.TEAM_DOMAIN, audience: env.POLICY_AUD, payload: payload, });
View logs:
npx wrangler tail
Symptoms:
- 404 when accessing custom domain
- DNS resolution fails
- SSL certificate errors
Solutions:
-
Verify domain is on Cloudflare:
- Domain must be managed by Cloudflare
- DNS must be proxied (orange cloud)
-
Check route configuration in wrangler.toml:
[[routes]] pattern = "r2.yourdomain.com" custom_domain = true
-
Verify DNS records:
- Go to Cloudflare Dashboard → DNS
- Should see CNAME or A record for subdomain
- Must be proxied (orange cloud icon)
-
Wait for DNS propagation:
- Can take 5-30 minutes for DNS changes
- Use
digornslookupto check:dig r2.yourdomain.com
-
Check SSL certificate:
- Cloudflare automatically provisions certificates
- May take a few minutes after DNS propagation
- Check in dashboard: SSL/TLS → Edge Certificates
Symptoms:
- Authentication works in Chrome but not Safari
- Cookies not being set in Safari
Solutions:
-
Disable "Prevent cross-site tracking":
- Safari → Preferences → Privacy
- Uncheck "Prevent cross-site tracking"
-
Or use Cloudflare Access for Safari:
- This is a Safari privacy feature
- Cloudflare Access should handle this automatically
- If issues persist, check Access configuration
Symptoms:
- API requests return 429 status code
- Error message: "Rate limit exceeded"
- Operations fail with "Please wait before retrying"
Solutions:
-
Wait before retrying:
- Check the
Retry-Afterheader in the response - Wait the specified duration (typically 60 seconds) before making more requests
- Rate limits reset automatically after the time period
- Check the
-
Reduce request frequency:
- Implement client-side caching for frequently accessed data
- Use bulk operations where available
- Batch multiple operations into fewer API calls
-
Check which tier is rate limiting:
- Review the
X-RateLimit-Tierheader in the response - READ tier: 100 requests per 60 seconds
- WRITE tier: 30 requests per 60 seconds
- DELETE tier: 10 requests per 60 seconds
- Review the
-
Implement exponential backoff:
async function retryWithBackoff(fn, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { return await fn(); } catch (error) { if (error.status === 429 && i < maxRetries - 1) { const retryAfter = error.headers.get("Retry-After") || 60; await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000), ); } else { throw error; } } } }
-
Check Worker logs for violations:
npx wrangler tail
Look for
[Rate Limit]entries showing which operations are being rate limited
Symptoms:
- Rate limits not being enforced
- No 429 responses when expecting them
- Rate limit violations not logged
Solutions:
-
Verify rate limiting bindings in wrangler.toml:
[[ratelimits]] name = "RATE_LIMITER_READ" namespace_id = "1001" simple = { limit = 100, period = 60 } [[ratelimits]] name = "RATE_LIMITER_WRITE" namespace_id = "1002" simple = { limit = 30, period = 60 } [[ratelimits]] name = "RATE_LIMITER_DELETE" namespace_id = "1003" simple = { limit = 10, period = 60 }
-
Check Wrangler version:
npx wrangler --version
Rate limiting requires Wrangler 4.36.0 or later. Update if necessary:
npm install -D wrangler@latest
-
Verify deployment succeeded:
npx wrangler deployments list
Ensure the latest deployment includes rate limiting configuration
-
Check if you're testing from localhost:
- Rate limiting is automatically disabled for
localhostrequests - Test from your deployed production URL instead
- Rate limiting is automatically disabled for
-
Verify Cloudflare Workers plan:
- Rate limiting requires a paid Cloudflare Workers plan ($5/month minimum)
- Check your plan at Cloudflare Dashboard
- To upgrade: Dashboard → Workers & Pages → Manage Subscription → Select Paid Plan
- Note: All other features work on the free tier
Symptoms:
- Want higher limits for admin users
- Need per-user or per-role rate limits
- Current tiered limits are too restrictive/permissive
Solutions:
-
Current implementation uses per-user limits:
- All authenticated users have the same rate limits
- Limits are enforced independently per user (by email)
- One user hitting limits doesn't affect others
-
To implement custom per-user limits (requires code modification):
Edit
worker/utils/ratelimit.ts:// Define user tiers const ADMIN_USERS = ["admin@example.com"]; const POWER_USERS = ["power@example.com"]; function getRateLimiter(env: Env, tier: RateLimitTier, userEmail: string) { // Give admins higher limits if (ADMIN_USERS.includes(userEmail)) { switch (tier) { case "READ": return { limiter: env.RATE_LIMITER_READ, limit: 500, period: 60 }; case "WRITE": return { limiter: env.RATE_LIMITER_WRITE, limit: 150, period: 60 }; case "DELETE": return { limiter: env.RATE_LIMITER_DELETE, limit: 50, period: 60 }; } } // Use default limits return getRateLimiter(env, tier); }
-
To adjust global rate limits:
Edit limits in
wrangler.toml:[[ratelimits]] name = "RATE_LIMITER_READ" namespace_id = "1001" simple = { limit = 200, period = 60 } # Increased from 100
Then redeploy:
npx wrangler deploy
Symptoms:
- Worker logs filled with rate limit violations
- Too many
[Rate Limit]entries - Difficult to find other log messages
Solutions:
-
This is expected behavior:
- All rate limit violations are logged for security monitoring
- Helps identify potential abuse or misconfigured clients
-
To reduce violations:
- Implement proper retry logic in your API client
- Add client-side request throttling
- Use caching to reduce redundant API calls
-
To filter logs:
# View only non-rate-limit logs npx wrangler tail | grep -v "Rate Limit" # View only rate limit violations npx wrangler tail | grep "Rate Limit"
-
To disable violation logging (not recommended):
Edit
worker/utils/ratelimit.tsand comment out the logging:if (!success) { // console.warn('[Rate Limit] Limit exceeded', { ... }); }
If you're still experiencing issues:
-
Check Worker logs:
npx wrangler tail
-
Enable debug mode:
- Add verbose logging to Worker
- Check browser console for errors
- Review Network tab in DevTools
-
Search GitHub Issues:
- Check existing issues
- Someone may have already solved your problem
-
Open a new issue:
- Visit GitHub Issues
- Include:
- Clear description of the problem
- Steps to reproduce
- Error messages and logs
- Browser and OS information
- Screenshots if relevant
-
Ask in Discussions:
- Visit GitHub Discussions
- For questions and general help
- Home - Documentation overview
- Quick Start Guide - Get up and running in minutes
- Installation & Setup - Complete deployment guide
- Configuration Reference - Environment variables and settings
- Upgrade Guide - Database schema migrations
- Bucket Management - Create, rename, delete buckets
- Object Lifecycles - Automate expiration and IA transitions ⭐ NEW
- Local Uploads - Faster uploads via nearby edge storage ⭐ NEW
- Job History - Track bulk operations with audit trail ⭐ NEW
- Webhooks - Configure HTTP notifications for events ⭐ NEW
- AI Search - Semantic search with Cloudflare AI
- S3 Import - Migrate from AWS S3 to R2 ⭐ NEW
- Cross-Bucket Search - Search across all buckets with filters
- File Operations - Upload, download, move, copy, delete files
- Folder Management - Organize files hierarchically
- Signed URLs & Sharing - Generate secure shareable links
- Advanced Filtering - Filter by extension, size, and date
- Development Guide - Local setup and development workflow
- API Reference - Complete endpoint documentation
- Architecture Overview - Technical stack and design
- Authentication & Security - Zero Trust implementation
- JWT Validation - JWT token validation and verification
- Troubleshooting - Common issues and solutions
- FAQ - Frequently asked questions
- Roadmap - Planned features and enhancements