{"record":{"id":"014db1f103f6e1c7","repo":"gitbutlerapp/gitbutler","slug":"silenterror-suppressed-from-query-error-telemetry","errorCode":null,"errorMessage":"SilentError suppressed from query:error telemetry","messagePattern":"SilentError suppressed from query:error telemetry","errorType":"console","errorClass":null,"httpStatus":null,"severity":"info","filePath":"apps/desktop/src/lib/error/error.ts","lineNumber":151,"sourceCode":"\treturn {\n\t\tname,\n\t\tmessage,\n\t\tcode,\n\t};\n}\n\nexport function emitQueryError(\n\tposthog: PostHogWrapper | undefined,\n\terror: unknown,\n\tcontext?: {\n\t\tcommand?: string;\n\t\tactionName?: string;\n\t\tseverity?: \"error\" | \"warning\" | \"silent\";\n\t},\n) {\n\tconst { name, message, code } = parseQueryError(error);\n\tif (name === \"SilentError\") {\n\t\tconsole.warn(\"SilentError suppressed from query:error telemetry\", error);\n\t\treturn;\n\t}\n\t// Errors classified `silent` are expected states (offline network blips,\n\t// known noise), not defects — keep them out of error telemetry.\n\tif (context?.severity === \"silent\") return;\n\tif (!posthog) return;\n\tconst key = `${context?.command ?? \"\"}|${name}`;\n\tif (!shouldCaptureQueryError(key)) return;\n\tposthog.capture(QUERY_ERROR_EVENT_NAME, {\n\t\terror_title: name,\n\t\terror_message: message,\n\t\terror_code: code,\n\t\tcommand: context?.command,\n\t\tactionName: context?.actionName,\n\t\tseverity: context?.severity,\n\t});\n}\n","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/apps/desktop/src/lib/error/error.ts#L133-L169","documentation":"emitQueryError classifies query errors via parseQueryError and forwards them to PostHog telemetry. Errors whose name is SilentError are intentional, expected conditions — cancellations and known-ignorable states — so the function warns to the console and returns before any telemetry capture. Seeing this message means a SilentError reached a query:error handler, exactly as designed.","triggerScenarios":"A Svelte query or mutation rejects with an error whose name is 'SilentError' (for example new SilentError('user cancelled')); emitQueryError detects name === \"SilentError\" at apps/desktop/src/lib/error/error.ts:151, logs the suppression, and skips capture.","commonSituations":"Cancellation-heavy flows (dialogs dismissed, operations superseded); accidentally naming an unrelated error class SilentError; debugging why a failure never appears in PostHog.","solutions":["Treat the message as expected bookkeeping — no action needed for genuine cancellations","If the console noise distracts during development, downgrade the warn to console.debug locally","If the error should actually be tracked, rename the throwing class away from SilentError so it stops matching the suppression branch","Double-check context.severity for errors that should be telemetry-silent without being SilentError"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function isSilentError(error: unknown): boolean {\n\treturn error instanceof Error && error.name === \"SilentError\";\n}","tryCatchPattern":"try {\n\tawait runSomeQuery();\n} catch (error) {\n\tif (isSilentError(error)) return; // expected cancellation — skip handling\n\thandleRealError(error);\n}","preventionTips":["Use SilentError only for user-visible cancellations and known ignorable states","Never reuse the name for real defects","Cover parseQueryError classification with unit tests"],"tags":["typescript","svelte","telemetry","error-classification"],"backgroundTag":"silently-swallowed-error","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}