ducaale/xh · error

expected \n\n

Error message

expected {}\n\n{}

What it means

`syntax_error` is the generic parser error for `--path-as-json`-style nested JSON path syntax. When `parse_path` encounters an unexpected character, it reports what was expected plus a `highlight_error` snippet pointing at the offending position in the user-supplied JSON path string.

Solutions

  1. Read the highlighted snippet in the error to locate the offending character and fix the path syntax at that position.
  2. Quote the whole argument in the shell to prevent bracket/quote mangling: `xh :8080 'users[0][name]==x'`.
  3. Consult the nested-JSON syntax rules (brackets, indices, quoted keys) and simplify the expression step by step.

Example fix

// before
xh :8080 users[0==bob
// after
xh :8080 'users[0]==bob'
Defensive patterns

Strategy: validation

Validate before calling

# pre-validate nested-JSON path args in scripts:
EXPR='users[0][name]==bob'
echo "$EXPR" | grep -qE "^[A-Za-z0-9_-]+(\[[^]]+\])*(==|:=|=)" || { echo "bad path expression: $EXPR"; exit 1; }

Try / catch

// parse the anyhow error and surface the highlighted snippet to the user:
if let Err(e) = run() { eprintln!("{e:#}"); std::process::exit(2); }

Prevention

When it happens

Trigger: Calling xh with a malformed nested-JSON path expression (e.g. `xh :8080 users[0]==name[`). Any unbalanced bracket, bad operator, or stray character in the path reaches `parse_path` and produces `expected <thing>` plus the highlighted snippet.

Common situations: Hand-writing complex `key[subkey]==value` expressions in shell where brackets/quotes get mangled; typos like `foo]=bar` or `foo[bar==baz`; shell interpolation eating quotes or escaping characters.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


AI-assisted analysis of ducaale/xh@2404aceecc (2026-09-13). Data as JSON: /api/errors/7f1516b8765d540c. Report an issue: GitHub.

Appendix: source

Thrown at src/nested_json.rs:238

/// with Value::null if needed
fn arr_insert(arr: &mut Vec<Value>, index: usize, value: Value) {
    while index >= arr.len() {
        arr.push(Value::Null);
    }
    arr[index] = value;
}

/// Removes an element from array and replace it with `Value::Null`.
fn remove_from_arr(arr: &mut [Value], index: usize) -> Option<Value> {
    if index < arr.len() {
        Some(mem::replace(&mut arr[index], Value::Null))
    } else {
        None
    }
}

fn syntax_error(expected: &'static str, pos: usize, json_path: &str) -> anyhow::Error {
    anyhow!(
        "expected {}\n\n{}",
        expected,
        highlight_error(json_path, pos, pos + 1)
    )
}

fn highlight_error(text: &str, start: usize, mut end: usize) -> String {
    use unicode_width::UnicodeWidthStr;
    // Apply right-padding so outside of the text could be highlighted
    let text = format!("{text:<end$}");
    // Ensure end doesn't fall on non-char boundary
    while !text.is_char_boundary(end) && end < text.len() {
        end += 1;
    }
    format!(
        "  {}\n  {}{}",
        text,
        " ".repeat(text[0..start].width()),

View on GitHub (pinned to 2404aceecc)