Context
After #15 (canvas client), #20 (docs client), and #18 (doctor's _check_devagentic_graph), three sites have the same dispatch on urllib.error.HTTPError / URLError / OSError / TimeoutError:
except urllib.error.HTTPError as exc:
if exc.code in (401, 403):
# auth-failure message
elif exc.code == 404:
# not-found message
else:
# generic HTTP message
except (urllib.error.URLError, OSError, TimeoutError) as exc:
# unreachable message
The messages differ per site (canvas/docs include the URL inline, doctor adds the #21 hint), but the classification logic is identical.
Fix
Add classify_http_error(exc) -> str to utils.py. Returns one of {"auth", "not_found", "http", "unreachable", "unknown"}. Callers dispatch on the return value and own their own message text.
Refactor:
plugins/devagentic-canvas/client.py:_request
plugins/devagentic-docs/client.py:_post_graphql
hermes_cli/doctor.py:_check_devagentic_graph
Same behavior; one place to add a new kind (e.g. "rate_limit" when more sites care).
Out of scope
- Mem0's message-substring classifier (
401/403/unauthorized/etc. in str(exc)). The mem0ai SDK doesn't surface HTTPError — it raises wrapped exceptions with the status in the message string. That's a different taxonomy and would need its own helper if/when another SDK uses the same shape. Not yet 3 sites.
- Touching the canvas/docs slash-command preambles — they intentionally don't classify (return None silently on any failure to preserve the loss-tolerant contract).
Filed by hermes-maintainer (PowerCreek). PR incoming.
Context
After #15 (canvas client), #20 (docs client), and #18 (doctor's
_check_devagentic_graph), three sites have the same dispatch onurllib.error.HTTPError/URLError/OSError/TimeoutError:The messages differ per site (canvas/docs include the URL inline, doctor adds the #21 hint), but the classification logic is identical.
Fix
Add
classify_http_error(exc) -> strtoutils.py. Returns one of{"auth", "not_found", "http", "unreachable", "unknown"}. Callers dispatch on the return value and own their own message text.Refactor:
plugins/devagentic-canvas/client.py:_requestplugins/devagentic-docs/client.py:_post_graphqlhermes_cli/doctor.py:_check_devagentic_graphSame behavior; one place to add a new kind (e.g.
"rate_limit"when more sites care).Out of scope
401/403/unauthorized/etc. instr(exc)). The mem0ai SDK doesn't surfaceHTTPError— it raises wrapped exceptions with the status in the message string. That's a different taxonomy and would need its own helper if/when another SDK uses the same shape. Not yet 3 sites.Filed by hermes-maintainer (PowerCreek). PR incoming.