{"record":{"id":"4ca2fe04036b67e2","repo":"slopus/happy","slug":"failed-to-read-settings-error-message","errorCode":null,"errorMessage":"Failed to read settings: ${error.message}","messagePattern":"Failed to read settings: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/happy-cli/src/persistence.ts","lineNumber":118,"sourceCode":"      );\n    }\n\n    // Migrate if needed\n    const migrated = migrateSettings(raw, schemaVersion);\n\n    if (migrated.sandboxConfig !== undefined) {\n      try {\n        migrated.sandboxConfig = SandboxConfigSchema.parse(migrated.sandboxConfig);\n      } catch (error: any) {\n        logger.warn(`⚠️ Invalid sandbox config - skipping. Error: ${error.message}`);\n        migrated.sandboxConfig = undefined;\n      }\n    }\n\n    // Merge with defaults to ensure all required fields exist\n    return { ...defaultSettings, ...migrated };\n  } catch (error: any) {\n    logger.warn(`Failed to read settings: ${error.message}`);\n    // Return defaults on any error\n    return { ...defaultSettings }\n  }\n}\n\nexport async function writeSettings(settings: Settings): Promise<void> {\n  if (!existsSync(configuration.happyHomeDir)) {\n    await mkdir(configuration.happyHomeDir, { recursive: true })\n  }\n\n  // Ensure schema version is set before writing\n  const settingsWithVersion = {\n    ...settings,\n    schemaVersion: settings.schemaVersion ?? SUPPORTED_SCHEMA_VERSION\n  };\n\n  await writeFile(configuration.settingsFile, JSON.stringify(settingsWithVersion, null, 2))\n}","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/slopus/happy/blob/b824cd0a4681d41af631a8e422a813873e4455b0/packages/happy-cli/src/persistence.ts#L100-L136","documentation":"readSettings wraps the entire load-and-migrate pipeline in a try/catch. If anything throws — unreadable file, malformed JSON, a bug in migration, or an unexpected error in merging — this warning is logged and default settings are returned so the CLI keeps working. It swallows the real error, so the message text is the only diagnostic.","triggerScenarios":"readSettings called (via settings() or current()) when the settings file is missing/unreadable, contains invalid JSON, or migrateSettings throws on an incompatible schemaVersion.","commonSituations":"Permissions problem on ~/.happy, partial/corrupt settings.json from a crashed write, JSON edited with trailing commas or comments, or an older settings file whose schemaVersion breaks migration.","solutions":["Check the error.message in the warning to see whether it's ENOENT, EACCES, or a JSON parse error.","Fix file permissions (chmod/chown) or restore the settings file; delete it to reset to defaults.","Validate the JSON (e.g. jq . ~/.happy/settings.json) and fix syntax errors.","Back up the file, delete it, and reconfigure happy from scratch."],"exampleFix":"// before (corrupt JSON)\n{ \"defaultMode\": \"sandbox\", }\n// after\n{ \"defaultMode\": \"sandbox\" }","handlingStrategy":"fallback","validationCode":"const p = require('os').homedir() + '/.happy/settings.json';\ntry {\n  JSON.parse(require('fs').readFileSync(p, 'utf8'));\n} catch (e) {\n  console.error(`Settings file ${p} is unreadable/invalid: ${e.message} — remove or fix it before running happy.`);\n}","typeGuard":null,"tryCatchPattern":"// happy already falls back to defaults internally; on your side:\ntry {\n  const settings = await readSettings();\n} catch (e) {\n  // note: readSettings itself swallows errors, so guard the file first\n  const defaults = { ...defaultSettings };\n}","preventionTips":["Validate settings JSON with `jq` or an editor with JSON linting before saving.","Ensure atomic writes (happy does tmp+rename); avoid killing the CLI mid-write.","Check file permissions on ~/.happy after OS/user changes.","Back up settings.json before upgrading happy."],"tags":["settings","file-io","json-parse","fallback"],"backgroundTag":"settings-file-corrupt","analyzedSha":"b824cd0a4681d41af631a8e422a813873e4455b0","analyzedAt":"2026-08-31T23:12:36.205Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}