marktext/marktext · critical · Error

Can not load static preference.json file

Error message

Can not load static preference.json file

What it means

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.

Source

Thrown at packages/desktop/src/main/preferences/index.ts:86

      // Set best theme on first application start.
      if (nativeTheme.shouldUseDarkColors) {
        defaultSettings!.theme = 'dark'
      }

      // Set system language on first application start
      if (!this.hasPreferencesFile) {
        const systemLanguage = this._getSystemLanguage()
        if (systemLanguage) {
          defaultSettings!.language = systemLanguage
        }
      }
    } catch (err) {
      log.error(err)
    }

    if (!defaultSettings) {
      throw new Error('Can not load static preference.json file')
    }

    // I don't know why `this.store.size` is 3 when first load, so I just check file existed.
    if (!this.hasPreferencesFile) {
      this.store.set(defaultSettings)
    } else {
      // Because `this.getAll()` will return a plainObject, so we can not use `hasOwnProperty` method
      // const plainObject = () => Object.create(null)
      const userSetting = this.getAll() as Record<string, unknown>
      // Update outdated settings
      const requiresUpdate = !hasSameKeys(defaultSettings, userSetting)
      const userSettingKeys = Object.keys(userSetting)
      const defaultSettingKeys = Object.keys(defaultSettings)

      if (requiresUpdate) {
        // TODO(fxha): For performance reasons, we should try to replace 'electron-store' because
        //   it does multiple blocking I/O calls when changing entries. There is no transaction or
        //   async I/O available. The core reason we changed to it was JSON scheme validation.

View on GitHub (pinned to e52106fd1c)

Solutions

  1. Rebuild static assets: `pnpm run build:unpack` and confirm preference.json is emitted under out/resources or static/.
  2. Verify global.__static is set correctly in main/config.js and points at the directory containing preference.json.
  3. Ship a hard-coded fallback default settings object so a missing file does not crash startup.
  4. Differentiate the error: log whether readFileSync or JSON.parse failed to speed diagnosis.

Example fix

// before
try {
  defaultSettings = JSON.parse(fs.readFileSync(this.staticPath, { encoding: 'utf8' }) || '{}')
} catch (err) { log.error(err) }
if (!defaultSettings) throw new Error('Can not load static preference.json file')
// after — bundled fallback
try {
  defaultSettings = JSON.parse(fs.readFileSync(this.staticPath, { encoding: 'utf8' }) || '{}')
} catch (err) {
  log.error('Failed to load preference.json, using bundled defaults', err)
  defaultSettings = BUNDLED_DEFAULT_SETTINGS
}
Defensive patterns

Strategy: fallback

Validate before calling

import fs from 'fs'
function preferenceJsonReadable(p: string): boolean {
  try { return fs.existsSync(p) && fs.readFileSync(p, 'utf8').trim().length > 0 }
  catch { return false }
}

Try / catch

try { /* load preference.json */ }
catch (e) { log.error('preference.json unreadable, using bundled defaults', e) }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of marktext/marktext@e52106fd1c (2026-08-12). Data as JSON: /api/errors/0513edb844b365f0. Report an issue: GitHub.