Skip to content

Hermes: config.yaml mcp_install and pre_llm_hook_install refused on Linux and Windows (regressed again in v0.10.4) #1631

Closed

Description

@DeusData

Filed from discussion #1560. Reported independently on Linux and Windows, no tracking issue until now, and it regressed again in v0.10.4.

Symptom

Two operations fail against the Hermes config:

error: agent_config agent=Hermes op=mcp_install          path=~/.hermes/config.yaml
error: agent_config agent=Hermes op=pre_llm_hook_install path=~/.hermes/config.yaml

Windows sees the same against %LOCALAPPDATA%\hermes\config.yaml.

The regression shape is the useful part

version mcp_install pre_llm_hook_install
0.10.2 fails fails
0.10.3 works fails
0.10.4 fails fails

Something fixed mcp_install in 0.10.3 and something else broke it again in 0.10.4. That bisect window is narrow and worth walking.

It is our writer, not the file

@Galaxy-VN hand-added the identical hook entry and it worked. So the file is writable, well-formed, and accepts the content we want to put in it — we are the ones refusing.

The file is a regular file owned by the reporter, mode 0600, ~19 KB.

Why this is not #1180 or #635

Neither covers a refused config write, which is why this had no tracking issue.

Leading hypothesis

The YAML editor fails closed on several structural conditions that a real 19 KB hand-maintained config plausibly hits: an inline comment on a field line (rejected deliberately, so a raw value cannot be silently truncated at #), unsupported YAML constructs, or anchors/aliases. All of them return the same -1, so we cannot currently tell which.

Asks

@iandol, @Galaxy-VN — the most useful thing would be the shape of the file rather than its contents: does ~/.hermes/config.yaml contain inline comments on the same line as a value (key: value # note), YAML anchors (&name / *name), or multi-document separators (---)? Any one of those would point straight at the refusing check.

Thank you both — the manual-hook experiment in particular is what makes this actionable rather than a guess.

Activity

  1. rg6304 commented on Aug 14, 2026

    @rg6304

    Root cause confirmed with an isolated reproduction on Windows (v0.10.4). This is a strict-YAML failure — the refusal is our parser, not the file.

    Answering the "Asks" directly: the real 16 KB hand-maintained config contains:

    1. Inline flow mappings key: {} / key: [] (34 occurrences in my file) → parsed as empty key/value, rejected by yaml_sequence_validate_document
    2. Block sequence items at column 0 (- hermes-cli, etc.) → rejected (indentation must be ≥1 level)
    3. Multi-line double-quoted scalars ending in a dangling \ (long personality strings with emoji/kaomoji) → yaml_scan_quote returns error
    4. * inside a plain scalar value — not a YAML alias, just literal asterisks in a personality string (*nuzzles your code*). yaml_range_has_unsupported rejects * outside quotes, so any plain (unquoted) scalar containing * fails.

    Bisection evidence: truncating the config line-by-line against install showed the exact failing line was a plain personality value containing *. Quoting it (single-quoted, doubling internal quotes) made that section pass.

    No anchors, no --- multi-doc separators, no inline # comments in this file — so the hypothesis in the issue is incomplete: the three named constructs (comments / anchors / separators) are not what tripped it. Plain-scalar *, flow {}/[], unindented sequences, and dangling \ continuations are the real offenders.

    Workaround that achieves EXIT 0: a lossless transform that (a) folds multi-line scalars to one line, (b) rewrites key: {} → key: (empty), (c) indents block sequences, (d) single-quotes any plain scalar containing {}&*. install -y --force then completes and all four client configs (Hermes, OpenCode, Gemini, VS Code) are written.

    Suggestions for the fix, from reading config_yaml_edit.c:

    • Fail-closed is the right default, but each refusing condition currently collapses to a single -1. Surfacing which check rejected (the same pattern cbm_daemon_ipc_validation_detail() uses elsewhere) would make every future report self-diagnosing.
    • yaml_range_has_unsupported could allow */& when they are interior characters of a scalar, not leading (a leading */& is an alias/anchor; interior * in prose is not).
    • For key: {} — treating an empty flow mapping as null (write key: alone) would be safe; the current rejection makes any config using empty collections un-editable.
  2. DeusData commented on Aug 14, 2026

    @DeusData
    OwnerAuthor

    This is a complete root cause with a reproduction, and it corrects my hypothesis rather than confirming it. Thank you — that is far more useful than agreement.

    I verified the sharpest of your four findings before replying. config_yaml_edit.c:1271:

    if (c == '{' || c == '}' || c == '&' || c == '*') {

    That rejects those characters anywhere in a plain scalar, with no positional test at all. Your distinction is exactly right and the code makes no attempt at it: a leading * or & is an alias or anchor; an interior one is just text. A personality string containing prose asterisks is not YAML we cannot model — it is YAML we declined to read.

    Your correction of the issue matters too, and I have marked it: I guessed inline comments, anchors, and --- separators. Your file has none of those. The real offenders are plain-scalar *, flow {}/[], unindented block sequences, and dangling \ continuations. That is four wrong guesses replaced by four verified causes, which is the difference between us fixing this and us shipping another partial fix.

    key: {} is the one I find least defensible. An empty flow mapping is ordinary YAML, and refusing it makes any config that uses empty collections permanently un-editable by us — 34 occurrences in one real file.

    On your first suggestion: you and I reached the same conclusion independently. #1629 is already open, adding observed detail to the refusal, and I noted there that the real fix is the editors carrying their own reason out the way cbm_daemon_ipc_validation_detail() does. Nine fail-closed conditions collapsing into one -1 is the reason this issue needed a stranger to reverse-engineer our parser. That is now clearly the highest-leverage item rather than merely a nice-to-have.

    Fix shape I am taking from this, in order:

    1. Positional test for */& — leading is an alias/anchor, interior is a character. Smallest change, unblocks the prose case.
    2. Empty flow mappings/sequences — treat key: {} and key: [] as null and write key:.
    3. Block sequences at column 0 — valid YAML; the indent requirement is ours, not the spec's.
    4. Dangling \ continuations in double-quoted scalars.
    5. Surface the refusing check, so the next one of these is self-diagnosing instead of requiring this much work from a reporter.

    Each needs a fixture from a real config rather than a synthetic one, which is precisely what you have given us.

    One question, if you are willing: would you be comfortable sharing a redacted skeleton of the file — structure preserved, values replaced — so it can go in as a regression fixture? Only if that is easy; your description is detailed enough that I can construct one, and I would rather not ask you for anything private.

    Genuinely: reproducing it in isolation, reading our source, and then correcting the maintainer's guess is about as good as a bug report gets.

  3. iandol commented on Aug 14, 2026

    @iandol

    My hermes config.yaml doesn't seem to have inline comments, yaml anchors or multi file separators. Does have some of the features mentioned by @rg6304

  4. DeusData commented on Aug 14, 2026

    @DeusData
    OwnerAuthor

    That corroborates @rg6304 precisely — two independent files, same constructs, and neither contains what I originally guessed. My hypothesis (inline comments, anchors, --- separators) is dead twice over now.

    The first of the four is fixed in #1639: an interior * in a plain scalar is text, not an alias. config_yaml_edit.c was rejecting & and * anywhere in a scalar with no positional test, so prose asterisks read as aliases. A leading one is still refused, as it should be.

    Remaining, in the order I intend to take them: empty flow mappings (key: {} — the least defensible of the four, since it makes any config using empty collections permanently un-editable), block sequences at column 0, and dangling \ continuations in double-quoted scalars.

    If you are willing, a redacted skeleton of your Hermes config — structure kept, every value replaced with a placeholder — would go in as a regression fixture. That way the fix is verified against a real file shape rather than something I invented, which matters here: I have now guessed wrong twice about what these files contain.

  5. iandol commented on Aug 15, 2026

    @iandol
  6. Galaxy-VN commented on Aug 15, 2026

    @Galaxy-VN

    @DeusData - Here is my config.yaml, note that my config is have hooks key add by manual, before when i update from v0.9.0 to v0.10.0 the config is same just no hooks key (As an aside, when I saw the install failed, I tried hooks: [] or hooks with values ​​and it still said install failed), mcp install work the pre_llm_call not so my is just that different from @iandol.

    https://gist.github.com/Galaxy-VN/38608008c4e9174b88a0ddcc89b14c47

  7. added a commit that references this issue on Aug 17, 2026
  8. DeusData commented on Aug 17, 2026

    @DeusData
    OwnerAuthor

    Landed on main in 93e9308 (PR #1683), shipping in v0.10.6. All four constructs from your and galaxy's real configs are accepted (empty flow collections, column-0 sequences, backslash-continued double-quoted scalars, mid-word quotes), plus repair of entries older cbm versions wrote. Both full reporter configs verified installing end-to-end with zero agent_config errors and every original line byte-preserved. Thank you both — and @rg6304 for the isolated repro that anchored the whole cluster.

  9. added a commit that references this issue on Aug 17, 2026
  10. imunique-ZJ commented on Aug 25, 2026

    @imunique-ZJ

    Hi, I still have this pre_llm_hook_install error.
    I found that it happens if there is an new line at the end of the config.yaml. When I remove the new lines, the installation completes without errors.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    stability/performanceServer crashes, OOM, hangs, high CPU/memorywindowsWindows-specific issues

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions