{"record":{"id":"17ee4899c4cd1ca4","repo":"gitbutlerapp/gitbutler","slug":"unable-to-log-error-to-file","errorCode":null,"errorMessage":"unable to log error to file","messagePattern":"unable to log error to file","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"apps/desktop/src/lib/backend/tauri.ts","lineNumber":195,"sourceCode":"\tconstructor(private store: Store) {}\n\n\tasync set(key: string, value: unknown): Promise<void> {\n\t\treturn await this.store.set(key, value);\n\t}\n\n\tasync get<T>(key: string, defaultValue: undefined): Promise<T | undefined>;\n\tasync get<T>(key: string, defaultValue: T): Promise<T>;\n\tasync get<T>(key: string, defaultValue?: T): Promise<T | undefined> {\n\t\tconst value = await this.store.get<T>(key);\n\t\treturn value !== undefined ? value : defaultValue;\n\t}\n}\n\nexport async function tauriLogErrorToFile(error: string) {\n\ttry {\n\t\tawait logErrorToFile(error);\n\t} catch (e: unknown) {\n\t\tconsole.warn(\"unable to log error to file\", e);\n\t}\n}\n\nexport function tauriPathSeparator(): string {\n\tconst platformName = platform();\n\treturn platformName === \"windows\" ? \"\\\\\" : \"/\";\n}\n\nasync function tauriGetAppInfo(): Promise<AppInfo> {\n\tconst [appName, appVersion] = await Promise.all([getName(), getVersion()]);\n\treturn { name: appName, version: appVersion };\n}\n\nasync function tauriInvoke<T>(command: string, params: Record<string, unknown> = {}): Promise<T> {\n\t// This commented out code can be used to delay/reject an api call\n\t// return new Promise<T>((resolve, reject) => {\n\t// \tif (command.startsWith('apply')) {\n\t// \t\tsetTimeout(() => {","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/apps/desktop/src/lib/backend/tauri.ts#L177-L213","documentation":"tauriLogErrorToFile wraps the Tauri log plugin's logErrorToFile IPC command so the UI can persist error text. The try/catch warns when the write fails — plugin not registered, log directory unwritable or full, or IPC torn down — and deliberately swallows the failure so diagnostics never crash the app. The cost is that the original error text is not persisted anywhere durable.","triggerScenarios":"Awaiting tauriLogErrorToFile(error) when the tauri-plugin-log command is not registered in the running build, the app-data log directory is read-only or the disk is full, or the call races window/app teardown so the IPC invoke rejects.","commonSituations":"A dev build started without the log plugin; permissions changed on the app-data directory; disk-full machines; logging triggered during webview shutdown or reload.","solutions":["Confirm tauri-plugin-log is registered on the Rust side and the app-data directory is writable","Free disk space or fix directory ownership so the log file can be written","Mirror the original error to console.error in the catch so it is not lost when the file write fails","Queue log writes and flush at startup instead of writing during teardown"],"exampleFix":"// before\nexport async function tauriLogErrorToFile(error: string) {\n\ttry {\n\t\tawait logErrorToFile(error);\n\t} catch (e: unknown) {\n\t\tconsole.warn(\"unable to log error to file\", e);\n\t}\n}\n\n// after\nexport async function tauriLogErrorToFile(error: string) {\n\ttry {\n\t\tawait logErrorToFile(error);\n\t} catch (e: unknown) {\n\t\tconsole.warn(\"unable to log error to file\", e);\n\t\tconsole.error(\"original error (file logging unavailable):\", error);\n\t}\n}","handlingStrategy":"fallback","validationCode":"async function canLogToFile(): Promise<boolean> {\n\ttry {\n\t\tawait logErrorToFile(\"\");\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}","typeGuard":"function isPluginCommandMissing(e: unknown): boolean {\n\treturn e instanceof Error && /command .* not found|plugin/i.test(e.message);\n}","tryCatchPattern":"try {\n\tawait logErrorToFile(error);\n} catch (e) {\n\tconsole.warn(\"unable to log error to file\", e);\n\tconsole.error(\"original error:\", error); // never lose the payload\n}","preventionTips":["Initialize the log plugin before rendering any UI","Verify the app-data directory is writable at startup","Keep a bounded in-memory log buffer as a secondary sink"],"tags":["typescript","tauri","logging","ipc","file-write"],"backgroundTag":"log-write-failed","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}