Automattic/harper · warning
Settings must be an object.
Error message
Settings must be an object.
What it means
Config::from_lsp_config expects the top-level LSP settings value to be a JSON object. Non-object values (null, array, scalar) are rejected because the server needs to look up the "harper-ls" key inside it.
Source
Thrown at harper-ls/src/config.rs:92
pub code_action_config: CodeActionConfig,
pub isolate_english: bool,
pub markdown_options: MarkdownOptions,
pub dialect: Dialect,
/// Maximum length (in bytes) a file can have before it's skipped.
/// Above this limit, the file will not be linted.
pub max_file_length: usize,
pub exclude_patterns: GlobSet,
}
impl Config {
pub fn from_lsp_config(workspace_root: &Path, value: Value) -> Result<Self> {
let mut base = Config::default();
let workspace_root = workspace_root.canonicalize()?;
let workspace_root = workspace_root.as_path();
let Value::Object(value) = value else {
bail!("Settings must be an object.");
};
let Some(Value::Object(value)) = value.get("harper-ls") else {
bail!("Settings must contain a \"harper-ls\" key.");
};
if let Some(v) = value.get("userDictPath") {
if !v.is_string() {
bail!("userDict path must be a string.");
}
let path = v.as_str().unwrap();
if !path.is_empty() {
base.user_dict_path = path.try_resolve_in(workspace_root)?.to_path_buf();
}
}
if let Some(v) = value.get("fileDictPath") {View on GitHub (pinned to 5fe7d5ab76)
Solutions
- Ensure the client sends settings as an object; on the server, short-circuit to Config::default() when settings is null.
- Fix your LSP client configuration so workspace settings are an object containing a "harper-ls" section.
- If triggering manually (e.g. via an LSP REPL), send {"harper-ls": {}} rather than null.
Example fix
// before
client.notify("workspace/didChangeConfiguration", { settings: null });
// after
client.notify("workspace/didChangeConfiguration", { settings: { "harper-ls": {} } }); Defensive patterns
Strategy: validation
Validate before calling
if (params.settings === null || typeof params.settings !== 'object') {
params.settings = { 'harper-ls': {} };
} Type guard
fn is_settings_object(v: &serde_json::Value) -> bool {
matches!(v, serde_json::Value::Object(_))
} Try / catch
match Config::from_lsp_config(value, workspace_root) {
Ok(cfg) => cfg,
Err(_) => Config::default(),
} Prevention
- Send an object (even empty) for settings rather than null from the client.
- On the server, short-circuit to defaults when settings is null.
- Test your LSP client's didChangeConfiguration payloads during setup.
When it happens
Trigger: A didChangeConfiguration notification or initialize options where `settings` is null or not an object — typical when the client sends an empty/null settings payload on startup.
Common situations: Editor clients that fire didChangeConfiguration with null settings before real config arrives; misconfigured LSP client setup passing the wrong value as settings; testing the server manually with non-object JSON.
Related errors
- The code action configuration must be an object.
- ForceStable must be a boolean value.
- userDict path must be a string.
- Settings must contain a "harper-ls" key.
- fileDict path must be a string.
AI-assisted analysis of Automattic/harper@5fe7d5ab76 (2026-09-06).
Data as JSON: /api/errors/ecf474a7c47a2322.
Report an issue: GitHub.