Skip to content

Troubleshooting

When a serverless app can’t render, the Crowdin host replaces it with a diagnostic panel. Each panel maps to a specific failure:

PanelWhat happened
This app has no bundle yetThe app has no JavaScript bundle to run - nothing was published and no dev server is linked
We couldn’t load the appThe bundle URL failed to load
The app is taking too long to loadThe bundle didn’t respond within a few seconds
The app didn’t startThe bundle loaded but never registered the expected module

Run publish to upload a bundle, or dev and accept the switch to the external bundle mode so Crowdin loads the app from your machine.

When the bundle URL points at localhost, check that the dev server is actually running on that port. Two browser-specific traps:

  • Chrome blocks requests to local addresses unless the page is allowed local network access - check the permission prompt or site settings.
  • Safari refuses plain-HTTP localhost requests from an HTTPS page, and the CLI dev server is HTTP-only - publish the bundle instead, or develop in another browser (a local HTTPS reverse proxy in front of the dev server also works).

For a published bundle, reload the page; if it persists, the uploaded bundle is broken - re-run publish.

The bundle URL is reachable but slow to respond. With a dev server, check it is running and reachable on that address (the first compile after startup can also take a moment - reload once it settles). For a published bundle, check your network connection and reload the page.

The bundle executed, but the host waited and no module matching context.app.type and key was registered. Typical causes:

  • Registration ran too late. prepare* calls must run synchronously at the top level of the bundle - not inside an async callback, a dynamic import, or an event handler.
  • Key mismatch. With several modules of one type in the manifest, each registration must pass its manifest key: prepareProjectMenu({ … }, "my-key").
  • Module type not registered at all. Every module type declared in the manifest must have a matching prepare* call in the bundle - one bundle serves them all.

The browser console shows what the SDK dispatcher resolved ([apps-sdk] no module registered for …).

The bundle only runs inside the Crowdin host - opened directly (e.g. http://localhost:8080/app.js or your external URL), the SDK has no host bridge to talk to and throws. To see the app, open it inside Crowdin: preview deep-links to the right page.

  • Translation catalogs are compiled once when dev starts - restart the dev server after editing .po files.
  • The local manifest.json and Crowdin’s copy can drift - manifest status shows the diff (and exits with code 1), manifest push / manifest pull resolve it.

The console shows Content Security Policy violations

Section titled “The console shows Content Security Policy violations”

The app iframe runs under a strict CSP. What it allows and forbids:

  • Allowed: fetch/XHR/WebSocket requests to any HTTPS host (plus localhost during development) - calling third-party APIs directly is fine; images, media, and fonts from https:, data:, and blob: URLs.
  • Forbidden: Web Workers (worker-src 'none' - breaks libraries that spawn workers, such as code editors or PDF renderers), nested iframes and embeds (frame-src/child-src 'none'), native form submissions (form-action 'none'), and scripts from anywhere but the app’s bundle.

A library that fails only inside Crowdin most likely hits one of these - the console’s CSP violation report names the blocked directive.

  • Every REST call must be covered by the scopes declared in the manifest - calls outside them are rejected, and an empty scopes array means no API access at all. Note that :write does not imply read access.
  • FormData bodies and GraphQL are not supported by the host bridge - see the API limitations.