Bug Description
I hit a reproducible crash in /journey and tracked it down to the learning graph builder.
Symptom
Running /journey failed with:
Code
· text
'NoneType' object has no attribute 'get'
In my local repro, the traceback landed here:
Code
· text
hermes_cli/journey.py -> agent/learning_graph.py -> _category()
More specifically, this line pattern was the problem:
Code
· python
fm.get("metadata", {}).get("hermes", {})
Root cause
/journey assumes parsed skill frontmatter always gives metadata.hermes as a dict.
In practice, some real SKILL.md files can parse into looser shapes, for example:
Code
· yaml
metadata:
or
Code
· yaml
metadata: oops
That means metadata may be None or a scalar instead of a mapping, and then the code calls .get() on something that is not a dict.
So this is not just “bad user input” in the abstract — it can happen with real skill files that the system is willing to read.
Expected behavior
/journey should degrade gracefully:
if metadata is missing, null, or malformed, treat it as empty
keep rendering the journey graph
fall back to other sources where possible (e.g. folder-derived category)
Actual behavior
A malformed or loosely parsed metadata field can crash /journey entirely.
Minimal fix direction
Normalize metadata.hermes before reading it:
if metadata is not a dict, use {}
if metadata.hermes is not a dict, use {}
then read category / related_skills from that safe mapping
That was enough in my local patch to stop the crash without thinning the overall journey data model. It just turns “fatal parse-shape mismatch” into “missing optional metadata”.
Verification
After applying that defensive guard locally:
/journey rendered successfully
targeted regression tests for
metadata:
metadata: oops passed
Why I think this is worth fixing
user-facing built-in command crash
small, low-risk robustness fix
behavior is consistent with other defensive metadata handling already present elsewhere in the codebase
If useful, I can also post the minimal patch shape, but I figured the bug report + root cause was the useful part first.
If you want, I can also compress that into a shorter, more forum-native version with less engineering detail.
Steps to Reproduce
- Run /journey from TUI
Expected Behavior
Journey graph output appears.
Actual Behavior
Received: "'NoneType' object has no attribute 'get'"
Affected Component
CLI (interactive chat)
Messaging Platform (if gateway-related)
No response
Debug Report
Report https://paste.rs/3yunm
agent.log https://paste.rs/OSp9U
gateway.log https://paste.rs/hlvVY
gui.log https://paste.rs/z0TxP
Operating System
Mac OS 26.5.1
Python Version
3.14.6
Hermes Version
0.18.0
Additional Logs / Traceback (optional)
Root Cause Analysis (optional)
No response
Proposed Fix (optional)
No response
Are you willing to submit a PR for this?
Bug Description
I hit a reproducible crash in /journey and tracked it down to the learning graph builder.
Symptom
Running /journey failed with:
Code
· text
'NoneType' object has no attribute 'get'
In my local repro, the traceback landed here:
Code
· text
hermes_cli/journey.py -> agent/learning_graph.py -> _category()
More specifically, this line pattern was the problem:
Code
· python
fm.get("metadata", {}).get("hermes", {})
Root cause
/journey assumes parsed skill frontmatter always gives metadata.hermes as a dict.
In practice, some real SKILL.md files can parse into looser shapes, for example:
Code
· yaml
metadata:
or
Code
· yaml
metadata: oops
That means metadata may be None or a scalar instead of a mapping, and then the code calls .get() on something that is not a dict.
So this is not just “bad user input” in the abstract — it can happen with real skill files that the system is willing to read.
Expected behavior
/journey should degrade gracefully:
if metadata is missing, null, or malformed, treat it as empty
keep rendering the journey graph
fall back to other sources where possible (e.g. folder-derived category)
Actual behavior
A malformed or loosely parsed metadata field can crash /journey entirely.
Minimal fix direction
Normalize metadata.hermes before reading it:
if metadata is not a dict, use {}
if metadata.hermes is not a dict, use {}
then read category / related_skills from that safe mapping
That was enough in my local patch to stop the crash without thinning the overall journey data model. It just turns “fatal parse-shape mismatch” into “missing optional metadata”.
Verification
After applying that defensive guard locally:
/journey rendered successfully
targeted regression tests for
metadata:
metadata: oops passed
Why I think this is worth fixing
user-facing built-in command crash
small, low-risk robustness fix
behavior is consistent with other defensive metadata handling already present elsewhere in the codebase
If useful, I can also post the minimal patch shape, but I figured the bug report + root cause was the useful part first.
If you want, I can also compress that into a shorter, more forum-native version with less engineering detail.
Steps to Reproduce
Expected Behavior
Journey graph output appears.
Actual Behavior
Received: "'NoneType' object has no attribute 'get'"
Affected Component
CLI (interactive chat)
Messaging Platform (if gateway-related)
No response
Debug Report
Operating System
Mac OS 26.5.1
Python Version
3.14.6
Hermes Version
0.18.0
Additional Logs / Traceback (optional)
Root Cause Analysis (optional)
No response
Proposed Fix (optional)
No response
Are you willing to submit a PR for this?