Skip to content

Troubleshooting

This page summarizes the likely causes, how to check, and how to fix five symptoms you commonly run into when using todoke. If you want to look up what a specific error code means, see Error codes and limits.

Symptom: A call to a send API such as POST /api/v1/notify, or via the CLI or SDK, succeeds (or does not error), yet no notification appears in the browser.

Likely causeHow to checkFix
The target subscription has been deactivated (it expired on the Push service side and was automatically invalidated after receiving 410 Gone / 404 Not Found)Check the “active subscribers” and “cumulative send failures” figures on the app detail screen in the dashboard, or with todoke apps stats <app-id> / GET /api/v1/apps/:id/statsRe-subscribe in the affected browser (run subscribe again). Deactivated subscriptions do not revive automatically
The Push service returned a transient server error (5xx) and retries were exhausted (after 3 retries per message, it is sent to the DLQ and that notification is lost)Confirm that “cumulative send failures” is increasing while “active subscribers” is not decreasing. Notifications that reach the DLQ are not resentThis is caused by a transient failure on the Push service side and cannot be prevented from your side. If an undelivered notification is important, resend it after a while. For details on how it works, see Architecture and how sending works
The Push service returned a 4xx other than 410 / 404 (only recorded as a delivery failure; no retry and no subscription invalidation)Suspect this case when “cumulative send failures” keeps rising but “active subscribers” does not dropIf it happens continuously for the same subscription, unsubscribe and re-register in that browser
The Free plan’s monthly send limit (30,000 messages) has been exceededCheck whether the response is 429 with code: "MONTHLY_LIMIT_EXCEEDED"Upgrade your plan or wait until the month rolls over. See Error codes and limits for details
The send payload exceeds the limit (3,072 bytes)Check whether the response is 413 with code: "PAYLOAD_TOO_LARGE"Reduce the combined size of title / body / url / icon / badge
Mistaking 202 Accepted for “delivered”Confirm that even if the response status is 202, it only means enqueuing to the Queue completedIt is not necessarily abnormal if it hasn’t arrived right after sending. Wait a little, then check success/failure in the statistics (above)

Symptom: Calling subscribe() on the frontend does not complete the subscription, or it errors.

Likely causeHow to checkFix
Calling from a non-HTTPS origin (Web Push requires HTTPS; localhost is an exception)Check the page’s URL scheme. If it is http:// and not localhost, the Push API itself is unavailableAlways serve over HTTPS in production-equivalent environments. Use http://localhost during development
The browser’s notification permission is blockedCheck the value of the browser’s Notification.permission (whether it is "denied"), or the notification permission state in the site settingsHave the user change the notification permission to “Allow” in the site settings. Once set to “Block”, you cannot re-prompt the dialog from code
The Free plan’s subscriber limit (1,000 people) has been exceededCheck whether the response is 429 with code: "SUBSCRIBER_LIMIT_EXCEEDED"Upgrade your plan or clean up existing inactive subscriptions. When the limit is reached, registering a new subscription may return 429
The Service Worker is not registeredCheck whether navigator.serviceWorker.getRegistration() returns undefinedComplete Service Worker registration (navigator.serviceWorker.register(...)) before calling subscribe

Symptom: An API call fails with an authentication/authorization error.

Likely causeHow to checkFix
The API key’s scope is insufficient (code: "INSUFFICIENT_SCOPE", 403)Compare the scope required by the endpoint you called with the scope of the API key you are using. For the operations allowed per scope, see API keysUse a key with a higher scope (notify / full)
The API key does not match the appId in the URL (code: "APP_MISMATCH", 403)Check whether the appId in the request URL matches the app that issued the API key you are usingUse the correct combination of appId and API key
The authentication header is missing or malformed, or the key/session is invalid (UNAUTHORIZED / INVALID_API_KEY / INVALID_SESSION, 401)Check whether the Authorization: Bearer <API key> header is correctly set and whether the key has not expiredFix the header format, or reissue the key in the dashboard. If the session has expired, log in again

For details on each code, see Error codes and limits.

Symptom: After repeated requests in a short time, requests are rejected with a 429 error.

Likely causeHow to checkFix
Reached the login (POST /auth/login) rate limit (10 times / 60 seconds / IP)Check the number of login attempts (successful or failed) within the last 60 secondsWait for the number of seconds in the response’s Retry-After before retrying
Reached the user registration (POST /auth/register) rate limit (5 times / 60 seconds / IP)Check the number of registration attempts (successful or failed) within the last 60 secondsSame as above. Wait for the Retry-After duration
Reached the API key authentication rate limit (20 times / 60 seconds / IP). This endpoint counts only authentication failuresCheck the number of API requests that failed authentication within the last 60 secondsWait for the Retry-After duration. Requests where the key succeeds correctly are not counted, so reviewing the key itself may also prevent recurrence

Symptom: Calling the todoke API directly with fetch from the browser blocks the request with a CORS error.

Likely causeHow to checkFix
The requesting origin is not in the allowlistCheck whether the page’s origin is one of: http://localhost(:port) / https://localhost(:port), https://todoke-dashboard.pages.dev, or a subdomain of *.todoke.devCall from an allowed origin, or change the setup so you call the API through your own server rather than directly from the frontend