{"record":{"id":"84c2c876b66299ce","repo":"commaai/openpilot","slug":"failed-to-read-cabana-settings-s-s-s","errorCode":null,"errorMessage":"failed to read Cabana settings %s%s%s\n","messagePattern":"failed to read Cabana settings (.+?)(.+?)(.+?)\n","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"openpilot/tools/cabana/settings.cc","lineNumber":81,"sourceCode":"  }\n  ~FileLock() {\n    if (fd >= 0) close(fd);\n  }\n  bool isLocked() const { return fd >= 0; }\n\nprivate:\n  int fd = -1;\n};\n\nLoadedSettings loadSettings() {\n  std::ifstream input(settingsFile());\n  if (!input) return {};\n\n  const std::string contents{std::istreambuf_iterator<char>(input), std::istreambuf_iterator<char>()};\n  std::string error;\n  auto settings_json = json11::Json::parse(contents, error);\n  if (!error.empty() || !settings_json.is_object()) {\n    fprintf(stderr, \"failed to read Cabana settings %s%s%s\\n\", settingsFile().c_str(), error.empty() ? \"\" : \": \", error.c_str());\n    return {.exists = true, .valid = false};\n  }\n  return {.values = settings_json.object_items(), .exists = true};\n}\n\nbool ensureSettingsDirectory() {\n  const auto path = settingsFile();\n  std::error_code error;\n  std::filesystem::create_directories(path.parent_path(), error);\n  if (error) {\n    fprintf(stderr, \"failed to create Cabana settings directory %s: %s\\n\", path.parent_path().c_str(), error.message().c_str());\n    return false;\n  }\n  return true;\n}\n\nbool writeAll(int fd, const std::string &data) {\n  size_t written = 0;","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/commaai/openpilot/blob/516ec1e68203439a73f340f1d0b3b91eabc626ee/openpilot/tools/cabana/settings.cc#L63-L99","documentation":"Emitted by loadSettings() in tools/cabana/settings.cc when the Cabana settings file (utils::configPath()/cabana.json) exists and was read, but json11::Json::parse returned a non-empty error string or the parsed document is not a JSON object. It is a stderr diagnostic, not a thrown exception; loadSettings returns {.exists=true, .valid=false} and the caller falls back to defaults (typically after preserving the corrupt file).","triggerScenarios":"Calling loadSettings() when cabana.json contains malformed JSON (truncated write, stray characters, BOM, trailing commas json11 rejects), or when the top-level JSON value is an array/string/number instead of an object. The ifstream open succeeded (otherwise the early `return {}` fires), so the file exists but its contents fail `json11::Json::parse(contents, error)` or `settings_json.is_object()`.","commonSituations":"Cabana killed mid-write in an older build that wrote the file non-atomically; hand-editing cabana.json and introducing a syntax error; disk-full truncation; a leftover file from a version with a different schema shape (e.g. top-level array).","solutions":["Fix or delete <configPath>/cabana.json and let Cabana regenerate it (a corrupt file is auto-renamed to cabana.json.corrupt by preserveCorruptSettings in the normal flow).","Check the printed parse error (the trailing ': <error>' part names the JSON position) and correct that spot in the file.","If the file is truncated from a crash, restore from cabana.json.corrupt.N backups or remove the file to start from defaults.","Verify HOME/XDG config dir is writable and on a healthy filesystem so future saves are not truncated."],"exampleFix":"// before (truncated/corrupt file):\n{\"openpilot\": {\"mode\": \"dark\"   // <- file cut off, json11 parse error\n\n// after:\n{\"openpilot\": {\"mode\": \"dark\"}}\n// or simply: rm ~/.comma/cabana.json  (path = utils::configPath()/cabana.json)","handlingStrategy":"validation","validationCode":"// Validate the settings file before loadSettings() is relied upon:\n#include <fstream>\n#include <json11.hpp>\nbool settingsFileValid(const std::filesystem::path &p) {\n  std::ifstream in(p);\n  if (!in) return false;                      // missing -> defaults, not an error\n  std::string contents{std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>()};\n  std::string err;\n  auto j = json11::Json::parse(contents, err);\n  return err.empty() && j.is_object();        // mirrors loadSettings()'s own check\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat cabana.json as machine-owned: edit settings via the cabana UI, not by hand.","Keep backups of a known-good cabana.json; corrupt files are auto-renamed to cabana.json.corrupt so recovery is one copy away.","Avoid killing cabana with SIGKILL; settings are saved atomically but a kill during first-write on old builds caused truncation."],"tags":["cabana","settings","json","parse-error","filesystem"],"backgroundTag":null,"analyzedSha":"516ec1e68203439a73f340f1d0b3b91eabc626ee","analyzedAt":"2026-08-15T00:17:37.461Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}