{"record":{"id":"0513edb844b365f0","repo":"marktext/marktext","slug":"can-not-load-static-preference-json-file","errorCode":null,"errorMessage":"Can not load static preference.json file","messagePattern":"Can not load static preference\\.json file","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/desktop/src/main/preferences/index.ts","lineNumber":86,"sourceCode":"\n      // Set best theme on first application start.\n      if (nativeTheme.shouldUseDarkColors) {\n        defaultSettings!.theme = 'dark'\n      }\n\n      // Set system language on first application start\n      if (!this.hasPreferencesFile) {\n        const systemLanguage = this._getSystemLanguage()\n        if (systemLanguage) {\n          defaultSettings!.language = systemLanguage\n        }\n      }\n    } catch (err) {\n      log.error(err)\n    }\n\n    if (!defaultSettings) {\n      throw new Error('Can not load static preference.json file')\n    }\n\n    // I don't know why `this.store.size` is 3 when first load, so I just check file existed.\n    if (!this.hasPreferencesFile) {\n      this.store.set(defaultSettings)\n    } else {\n      // Because `this.getAll()` will return a plainObject, so we can not use `hasOwnProperty` method\n      // const plainObject = () => Object.create(null)\n      const userSetting = this.getAll() as Record<string, unknown>\n      // Update outdated settings\n      const requiresUpdate = !hasSameKeys(defaultSettings, userSetting)\n      const userSettingKeys = Object.keys(userSetting)\n      const defaultSettingKeys = Object.keys(defaultSettings)\n\n      if (requiresUpdate) {\n        // TODO(fxha): For performance reasons, we should try to replace 'electron-store' because\n        //   it does multiple blocking I/O calls when changing entries. There is no transaction or\n        //   async I/O available. The core reason we changed to it was JSON scheme validation.","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/marktext/marktext/blob/e52106fd1cdcbd33c1258b7b0cdc7013c4c5d86c/packages/desktop/src/main/preferences/index.ts#L68-L104","documentation":"Thrown by Preferences.init() when defaultSettings is still null after the try/catch that reads and JSON.parses static/preference.json. The catch logs but leaves defaultSettings null, so the subsequent guard converts any read/parse failure of the bundled preference.json into a fatal startup error.","triggerScenarios":"fs.readFileSync(this.staticPath) fails (file missing — global.__static points at an unbuilt resources dir); JSON.parse fails (corrupt preference.json shipped in the build); the file is empty so parsing '{}' fallback is bypassed because readFileSync threw first.","commonSituations":"A production build where electron-vite did not copy static/preference.json into resources. A dev run with global.__static misconfigured. A manually corrupted preference.json in the package. This blocks the entire app from starting.","solutions":["Rebuild static assets: `pnpm run build:unpack` and confirm preference.json is emitted under out/resources or static/.","Verify global.__static is set correctly in main/config.js and points at the directory containing preference.json.","Ship a hard-coded fallback default settings object so a missing file does not crash startup.","Differentiate the error: log whether readFileSync or JSON.parse failed to speed diagnosis."],"exampleFix":"// before\ntry {\n  defaultSettings = JSON.parse(fs.readFileSync(this.staticPath, { encoding: 'utf8' }) || '{}')\n} catch (err) { log.error(err) }\nif (!defaultSettings) throw new Error('Can not load static preference.json file')\n// after — bundled fallback\ntry {\n  defaultSettings = JSON.parse(fs.readFileSync(this.staticPath, { encoding: 'utf8' }) || '{}')\n} catch (err) {\n  log.error('Failed to load preference.json, using bundled defaults', err)\n  defaultSettings = BUNDLED_DEFAULT_SETTINGS\n}","handlingStrategy":"fallback","validationCode":"import fs from 'fs'\nfunction preferenceJsonReadable(p: string): boolean {\n  try { return fs.existsSync(p) && fs.readFileSync(p, 'utf8').trim().length > 0 }\n  catch { return false }\n}","typeGuard":null,"tryCatchPattern":"try { /* load preference.json */ }\ncatch (e) { log.error('preference.json unreadable, using bundled defaults', e) }","preventionTips":["Bundle a default-settings object so a missing preference.json cannot crash startup.","Verify electron-vite copies static/preference.json into resources in the build pipeline.","Differentiate readFileSync vs JSON.parse failures in the log.","Add a smoke test that boots the main process with preference.json absent."],"tags":["preferences","startup","config","build"],"backgroundTag":null,"analyzedSha":"e52106fd1cdcbd33c1258b7b0cdc7013c4c5d86c","analyzedAt":"2026-08-12T13:58:32.443Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}