fix(desktop): report an offline cloud API on plugins.sync as unavailable
Problem
When the desktop app cannot reach the Paradev cloud API (a connect timeout, DNS failure, or refused connection), the plugins.sync mutation fails with a raw tRPC client "fetch failed" error. The main-process Sentry middleware reports every INTERNAL_SERVER_ERROR as a bug, and OrganizationPluginSync retries with backoff, so a machine that is offline sends one report per retry. This family has opened several desktop issues in the last day (one has 100+ events). Each one was archived on its own, and new ones keep opening whenever the bundle chunk hash changes.
Root cause
The middleware's contract says that expected states must be translated into non-500 errors at the throw site. plugins.sync has no such translation. The cause chain (tRPC client error → TypeError: fetch failed → undici UND_ERR_CONNECT_TIMEOUT) is exactly the case that host-service already classifies with rethrowCloudUnreachable, but the desktop router does not use it.
Fix
- Expose the existing
cloud-api-errormodule as the@superset/host-service/cloud-api-errorsubpath. Its only imports are a string constant and a type. - In
plugins.sync, catch the error, callrethrowCloudUnreachable(error), then rethrow. This is the same pattern ashost.ts. Transport failures becomeSERVICE_UNAVAILABLE. Every other failure (an application error, an unparsable response, or an error with no code) still reports as a 500.
Both packages resolve to the same @trpc/server@11.16.0 install, so the TRPCError from host-service is the instance the desktop router recognizes.
No product behaviour change except the error text: an uninstall toast that fails while offline now says "Could not reach the Paradev cloud API: …" instead of "fetch failed". This string already comes from host-service and is not new copy.
Verification
bunx biome check apps/desktop/src/lib/trpc/routers/plugins/index.ts packages/host-service/package.json→Checked 2 files in 74ms. No fixes applied.cd apps/desktop && bunx tsc --noEmit(run withNODE_OPTIONS=--max-old-space-size=6144, becausebun run typecheckwas OOM-killed on this sandbox) → exit 0, no outputcd packages/host-service && bun test src/trpc/router/host/cloud-api-error.test.ts→26 pass, 0 fail. These tests already cover the exact three-level undici chain, plus the negatives: a coded non-transport error, an uncoded error, and aSyntaxError.- No new tests. The classifier is unchanged and already tested; this PR only connects it.
Refs DESKTOP-1QS
Summary by cubic
Stops offline cloud API failures on plugins.sync from flooding Sentry with 500 errors. The desktop router now catches transport failures (connect timeout, DNS failure, refused connection) and classifies them as SERVICE_UNAVAILABLE, matching the pattern host.ts already uses.
- Exposes
rethrowCloudUnreachablefrom@superset/host-service/cloud-api-erroras a package subpath. - Only transport failures are translated; application errors, unparsable responses, and uncoded errors still report as 500s.
- The only user-visible change is the error text when offline, which now says "Could not reach the Paradev cloud API: …" instead of "fetch failed".
Summary by CodeRabbit
- Bug Fixes
- Plugin synchronization now handles cloud connection failures consistently, making unavailable-cloud errors clearer instead of masking them.