Troubleshooting Guide
Solve common issues with configuration, deployment, and runtime behavior.
Configuration Issues
"Config is invalid" on validate or deploy
The config file doesn't pass schema validation. Run bsl validate to see the specific errors. Common causes:
- Missing required fields — Check that
settings,links, andtrackersare all present at the top level. - Invalid URL format — All URLs (
fallback_url,redirect_url, tracker endpoints) must be valid URLs. Tracker URLs forntfy,posthog, andplain-textmust start withhttps://. - Invalid shortcode — Shortcodes must start with
/and be at least 2 characters (e.g.,/gis the minimum). - Wrong HTTP response code — Only
301,302,303,307, and308are accepted. - Extra fields on trackers — Trackers don't accept extra fields. Adding fields that don't belong to the tracker type (e.g.,
api_secreton afacebooktracker) causes validation failure. - Invalid ntfy token — The
tokenfield onntfytrackers must start withtk_.
Duplicate shortcode or tracker name errors
Each shortcode and each tracker name must be unique within the config. The validate command checks for duplicates beyond what schema validation catches.
Config file not found
The CLI checks these locations in order: current working directory, project root, ~/.config/branded-short-links/. If you're running the CLI from an unexpected directory, pass in from the correct location or move your config.json to the user config directory.
Deployment Issues
API token verification fails
- Confirm your token hasn't expired in the Cloudflare dashboard.
- Verify the token has the three required permission scopes: Account > Workers Scripts > Edit, Zone > Workers Routes > Edit, Zone > Email Routing Rules > Edit.
- Make sure the token's zone permissions include the zone that contains your
base_domain.
Permission verification fails for the base domain
The CLI resolves the Cloudflare zone by trying progressively shorter domain segments. If your base_domain is a subdomain (e.g., go.example.com), make sure the token has access to the parent zone (example.com).
Lint fails during deploy
The deploy pipeline runs ESLint against ./src. Any error blocks the deployment. Fix lint issues before redeploying:
npm run check:lint
wrangler deploy fails
- Verify Wrangler is installed as a dependency (
npm install). - Check that your Cloudflare account ID is correct. The CLI derives it from the zone information during permission verification.
- If you see authentication errors, your API token may lack the Workers Scripts Edit permission.
DNS and SSL Issues
DNS_PROBE_FINISHED_NXDOMAIN
The browser or curl says the domain cannot be resolved. The custom domain route was deployed but Cloudflare hasn't created the DNS record yet, or DNS hasn't propagated.
- Wait a few minutes after deploy. Cloudflare auto-creates DNS records for Workers custom domains.
- Verify in Dashboard > DNS > Records that a record exists for your domain.
- Verify in Dashboard > Workers & Pages > your-worker > Settings > Domains & Routes that the custom domain is listed.
- Check propagation:
dig yourdomain.com
ERR_SSL_VERSION_OR_CIPHER_MISMATCH
The browser shows an SSL error when accessing the custom domain. Cloudflare hasn't provisioned the SSL certificate yet.
- Wait up to 15 minutes. Certificate provisioning happens automatically.
- Check Dashboard > SSL/TLS > Edge Certificates for certificate status.
- Ensure your SSL/TLS mode is set to "Full" or "Full (strict)" in Dashboard > SSL/TLS > Overview.
403 Forbidden (Cloudflare HTML page)
POST requests or automated tools return a Cloudflare "Sorry, you have been blocked" HTML page instead of reaching the worker. Bot Fight Mode or WAF rules are blocking the requests.
- Option 1: Disable Bot Fight Mode at Dashboard > Security > Bots > Bot Fight Mode > Off.
- Option 2: Create a WAF skip rule at Dashboard > Security > WAF > Custom Rules:
- Condition:
(http.host contains "yourdomain.com") - Action: Skip > All Super Bot Fight Mode Rules
- Position: First
- Condition:
- Option 3: Block by geography instead:
(http.host contains "yourdomain.com") and (not ip.geoip.country in {"US" "CA"})with action Block.
Free plan users cannot skip Bot Fight Mode via WAF rules. You'd need to either disable it entirely or upgrade to Pro.
TLS Handshake Failure (from Docker Containers)
Containers (e.g., Watchtower, webhook runners) fail with remote error: tls: handshake failure when sending requests through your worker. The container's CA certificate bundle is outdated (baked in at image build time) and doesn't trust Cloudflare's edge certificate chain.
Mount the host's CA certificates into the container:
-v /etc/ssl/certs:/etc/ssl/certs:ro
On Synology NAS, the cert path is /etc/ssl/certs/. Add this volume mount to your Docker run command or compose file and restart the container.
Runtime Issues
Trackers not firing
- Check that your tracker credentials are correct (API secrets, tokens, pixel IDs).
- Tail the worker logs to see tracker dispatch activity:
npm run tail
- Each tracker fires independently. A failure in one tracker doesn't affect others.
- Tracker errors are silently handled — failures are not logged to the worker logs. Check the individual analytics service dashboards to confirm events are arriving.
- To debug tracker issues, consider adding a plain-text tracker pointing to an endpoint you control (e.g., an ntfy topic or a request bin) so you can verify payloads are being sent.
Redirect goes to fallback instead of matching shortcode
- Shortcodes are matched exactly (after stripping the trailing slash). Check that your config shortcode matches the path you're requesting.
- Shortcodes must include the leading
/(e.g.,/github, notgithub). - Paths with a trailing slash are stripped before matching, so
/github/matches/github. However, additional path segments don't match (e.g.,/github/reposdoesn't match/github).
Landing page shows instead of redirect
The landing page is served when:
- The request hits the root path (
/) and nofallback_urlis configured. - The request hits an unmatched path and no
fallback_urlis configured (this shows the 404 page).
If you want all unmatched requests to redirect somewhere, set a fallback_url in your config.
405 Method Not Allowed
The worker only accepts GET and HEAD requests. POST, PUT, DELETE, and other methods return a 405 JSON response. This is expected behavior for a URL shortener.
Debug output on landing page
If you see config output on the landing page, show_response_output is set to true. Sensitive values (API secrets, tokens, measurement IDs) are masked with ••••••, but you'd still want to set this to false in production.
Limiting Unwanted Traffic
After deployment, you may see unwanted traffic probing for exploits. You can set up a Cloudflare WAF rule to mitigate.
WAF Rule Setup
- Go to Dashboard > Security > WAF > Custom Rules.
- Create a rule with these conditions using the expression builder:
- Select Known Bots from the Field dropdown and set it to enabled.
- Select Threat Score from the Field dropdown and set it to greater than or equal to
5. - Select URI Path from the Field dropdown and set it to does not equal
/github(repeat for each of your shortcodes).
- Set the action to Managed Challenge.
Example Expression
If your shortcodes are /github and /linkedin, the WAF rule expression looks like:
(cf.bot_management.score lt 30) or
(cf.threat_score ge 5) and
(http.request.uri.path ne "/github") and
(http.request.uri.path ne "/linkedin")
This blocks automated scanners and high-threat-score traffic while allowing legitimate visitors to reach your configured shortcodes. Adjust the shortcode paths to match your configuration.