Automattic/harper · warning
userDict path must be a string.
Error message
userDict path must be a string.
What it means
Inside Config::from_lsp_config, the optional `userDictPath` setting must be a JSON string if present. Non-string values abort config parsing. When the string is non-empty it is resolved relative to the workspace root; empty strings are ignored (default dictionary used).
Source
Thrown at harper-ls/src/config.rs:101
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") {
if !v.is_string() {
bail!("fileDict path must be a string.");
}
let path = v.as_str().unwrap();
if !path.is_empty() {
base.file_dict_path = path.try_resolve_in(workspace_root)?.to_path_buf();
}
}View on GitHub (pinned to 5fe7d5ab76)
Solutions
- Set userDictPath to a string path, e.g. "userDictPath": "./user-dict.txt".
- Remove the key to use the default dictionary location.
- If generating settings programmatically, ensure paths are converted to strings (and use empty string "" explicitly to mean 'no custom dict').
Example fix
// before
{ "harper-ls": { "userDictPath": ["dict.txt"] } }
// after
{ "harper-ls": { "userDictPath": "dict.txt" } } Defensive patterns
Strategy: validation
Validate before calling
const p = settings?.['harper-ls']?.userDictPath;
if (p !== undefined && typeof p !== 'string') {
throw new TypeError('userDictPath must be a string');
} Type guard
fn is_optional_string(v: &serde_json::Value) -> bool {
v.get("userDictPath").map_or(true, |s| s.is_string())
} Try / catch
match Config::from_lsp_config(value, workspace_root) {
Ok(cfg) => cfg,
Err(e) => { log::warn!("invalid userDictPath: {e}"); Config::default() }
} Prevention
- Always write userDictPath as a quoted string path in settings.
- Convert Path objects to strings before embedding them in generated settings.
- Remember empty string means 'use default' — prefer omitting the key unless customizing.
When it happens
Trigger: Sending {"harper-ls": {"userDictPath": 42}} or an array/object for userDictPath via LSP settings.
Common situations: Editor settings where the path was written as a list or with wrong type; tooling that programmatically builds settings and passes a Path object that serializes as a non-string; typos in config generators.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- The code action configuration must be an object.
- ForceStable must be a boolean value.
- Settings must be an object.
- 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/1d35fd9b0116a97c.
Report an issue: GitHub.