fix(skills): tolerate non-UTF-8 bytes in hub lock.json (#68053) - #68062
Closed
PRATHAMESH75 wants to merge 1 commit into
Closed
fix(skills): tolerate non-UTF-8 bytes in hub lock.json (#68053)#68062PRATHAMESH75 wants to merge 1 commit into
PRATHAMESH75 wants to merge 1 commit into
Conversation
_read_hub_installed_names() reads ~/.hermes/skills/.hub/lock.json with a strict utf-8 decode. Hub skill descriptions can carry Windows-1252 typographic bytes (em-dash 0x97, smart quotes, bullets) as single high bytes; read_text(encoding="utf-8") then raises UnicodeDecodeError, which is a ValueError sibling not caught by the function's except (OSError, json.JSONDecodeError). It escapes and 500s the whole /api/skills endpoint, blanking the desktop Skills panel. Decode with errors="replace" so the offending byte degrades to U+FFFD and the structurally valid JSON — and every other skill — stays readable. Fixes NousResearch#68053
Bryntly
reviewed
Jul 20, 2026
Bryntly
left a comment
There was a problem hiding this comment.
LGTM. The use of errors='replace' effectively mitigates the UnicodeDecodeError by replacing invalid UTF-8 bytes like Windows-1252 typographics with the Unicode Replacement Character (U+FFFD). This allows json.loads to parse the structure successfully instead of crashing the API endpoint. Tests are comprehensive and CI is green.
Contributor
|
Merged via PR #71078 — your commit(s) were cherry-picked onto current main with your authorship preserved in git log (rebase merge). This PR was part of the class-wide close-out of bare |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
tools/skill_usage.py::_read_hub_installed_names()reads~/.hermes/skills/.hub/lock.jsonwith a strict UTF-8 decode:json.loads(lock_path.read_text(encoding="utf-8")). Hub skill descriptions can contain Windows-1252 typographic characters (em-dash0x97, smart quotes, bullets) written as single high bytes.read_text(encoding="utf-8")then raisesUnicodeDecodeError.UnicodeDecodeErroris aValueErrorsibling — it is not caught by the function'sexcept (OSError, json.JSONDecodeError), so it escapes and propagates up throughweb_server.py'sget_skillshandler, returning HTTP 500 for the entire/api/skillsendpoint. The result: the desktop Capabilities/Skills panel goes blank and users can't see or toggle any skill, all because of one bad byte in a description field.This decodes the lock file with
errors="replace", so the offending byte degrades toU+FFFDand the structurally valid JSON — including every other skill name — stays readable. This heals both existing corrupted lock files and any written in the future, regardless of where the cp1252 byte originated.Related Issue
Fixes #68053
(Addresses Problem 1 — the
/api/skills500. Problem 2 in that issue, stalehermes-agent.broken-*backup-dir cleanup, is a separate concern and out of scope for this focused fix.)Type of Change
Changes Made
tools/skill_usage.py—_read_hub_installed_names()now readslock.jsonwithread_text(encoding="utf-8", errors="replace")instead of a strict decode, with a comment explaining whyUnicodeDecodeErrorwould otherwise escape the handler.tests/tools/test_hub_lock_non_utf8_68053.py— regression tests: a lock file with a raw0x97em-dash byte no longer raises and the skill name is still recovered; a clean UTF-8 lock still reads unchanged.How to Test
Result:
2 passed. Reverting theerrors="replace"change makestest_windows_1252_em_dash_does_not_raisefail with the exactUnicodeDecodeError: 'utf-8' codec can't decode byte 0x97from the issue traceback. Existingtests/tools/test_skill_usage.py(47 tests) still pass.Checklist
Code
Documentation & Housekeeping
cli-config.yaml.example— N/ACONTRIBUTING.md/AGENTS.md— N/A