Title
oikb validate --deep crashes with cryptic TypeError: ('parser', <class 'module'>) on Windows — actual cause is stale trio incompatible with Python 3.13's pathlib.Path.parser
Summary
On Windows, oikb validate --deep (and in fact any oikb command that constructs an httpx.Client) can fail with a confusing, non-actionable error:
Deep validation
✗ Cannot reach Open WebUI: ('parser', <class 'module'>)
This looks like a network/connectivity problem, but it isn't — httpx.Client() never even gets to make a request. The root cause is an environment issue (outdated trio), but oikb's error handling in cli.py swallows the real traceback and prints only str(e), which for multi-arg exceptions is just repr(e.args). This makes the message actively misleading for anyone trying to diagnose a "connectivity" failure that has nothing to do with the network.
Environment
- OS: Windows (PowerShell)
- Python: 3.13.x
- oikb: 0.4.0
- httpx: 0.28.1
- httpcore: 1.0.9
- trio: 0.23.1 (before fix) — pulled in transitively via
selenium / trio-websocket, used by httpcore._synchronization for sync primitives
Root cause
httpcore._synchronization imports trio on Windows for its locking primitives. trio's _path.py defines trio.Path by wrapping every method of pathlib.Path/PurePath via a metaclass (AsyncAutoWrapperType.generate_forwards), iterating over pathlib.Path's class attributes.
Python 3.13 added a new class attribute to pathlib.PurePath: parser (a module reference, e.g. posixpath/ntpath, part of the new path-flavour abstraction). Older versions of trio (e.g. 0.23.1) assume every wrapped attribute is callable/descriptor-like and blow up when it encounters a bare module:
# trio/_path.py, generate_forwards()
raise TypeError(attr_name, type(attr))
# -> TypeError('parser', <class 'module'>)
This exception propagates all the way up through httpcore → httpx.Client.__init__ → oikb._make_client(), where cli.py catches it as a generic Exception and prints:
except Exception as e:
click.echo(click.style(f" ✗ Cannot reach Open WebUI: {e}", fg="red"))
Since the TypeError was raised with two positional args, str(e) renders as repr(e.args) — hence the odd ('parser', <class 'module'>) output, with zero indication that this is an import-time failure unrelated to networking.
Fix on the user side: pip install --upgrade trio (0.23.1 → 0.33.0 resolves it).
Reproduction
python -c "import httpx; httpx.Client()"
On an affected environment (Python 3.13 + trio < ~0.26) this raises the traceback below instead of returning silently.
Full traceback
Traceback (most recent call last):
File "<string>", line 1, in <module>
import httpx; httpx.Client()
File "...\httpx\_client.py", line 688, in __init__
self._transport = self._init_transport(...)
File "...\httpx\_client.py", line 731, in _init_transport
return HTTPTransport(...)
File "...\httpx\_transports\default.py", line 150, in __init__
import httpcore
File "...\httpcore\__init__.py", line 1, in <module>
from ._api import request, stream
File "...\httpcore\_api.py", line 7, in <module>
from ._sync.connection_pool import ConnectionPool
File "...\httpcore\_sync\__init__.py", line 1, in <module>
from .connection import HTTPConnection
File "...\httpcore\_sync\connection.py", line 14, in <module>
from .._synchronization import Lock
File "...\httpcore\_synchronization.py", line 12, in <module>
import trio
File "...\trio\__init__.py", line 77, in <module>
from ._path import Path as Path
File "...\trio\_path.py", line 201, in <module>
class Path(metaclass=AsyncAutoWrapperType):
File "...\trio\_path.py", line 145, in __init__
type(cls).generate_forwards(cls, attrs)
File "...\trio\_path.py", line 162, in generate_forwards
raise TypeError(attr_name, type(attr))
TypeError: ('parser', <class 'module'>)
Suggested fixes for oikb
None of this is oikb's bug per se (it's an upstream trio/Python 3.13 incompatibility), but oikb's error handling makes it very hard to diagnose. Suggestions, roughly in order of preference:
- In
_make_client() / the validate --deep handler, catch import/construction errors from httpx.Client() separately and print the full exception type + traceback (or at least repr(e) instead of str(e)) so users can see it's a TypeError on import, not a connection failure.
- Consider whether
httpcore's optional trio backend needs to be pulled in at all for oikb's use case (oikb only uses the sync httpx.Client, not httpx.AsyncClient) — if there's a way to avoid triggering the trio import path for sync-only usage, that would sidestep this class of issue entirely.
- Document a minimum
trio version (or add trio>=0.26 as an explicit constraint) in pyproject.toml if httpcore/trio end up in the dependency tree on Windows, since older trio is incompatible with Python 3.13.
- At minimum, mention this failure mode in the troubleshooting docs — "Cannot reach Open WebUI: ('parser', <class 'module'>)" is a decent search-engine anchor for future users hitting the same thing.
Additional notes
Direct connectivity to Open WebUI was confirmed working the whole time (curl -i $OPEN_WEBUI_URL/health returned 200 OK) while oikb validate --deep reported "Cannot reach Open WebUI" — worth flagging explicitly in any fix/doc update that this message can be a false negative for network reachability.
Title
oikb validate --deepcrashes with crypticTypeError: ('parser', <class 'module'>)on Windows — actual cause is staletrioincompatible with Python 3.13'spathlib.Path.parserSummary
On Windows,
oikb validate --deep(and in fact anyoikbcommand that constructs anhttpx.Client) can fail with a confusing, non-actionable error:This looks like a network/connectivity problem, but it isn't —
httpx.Client()never even gets to make a request. The root cause is an environment issue (outdatedtrio), but oikb's error handling incli.pyswallows the real traceback and prints onlystr(e), which for multi-arg exceptions is justrepr(e.args). This makes the message actively misleading for anyone trying to diagnose a "connectivity" failure that has nothing to do with the network.Environment
selenium/trio-websocket, used byhttpcore._synchronizationfor sync primitivesRoot cause
httpcore._synchronizationimportstrioon Windows for its locking primitives.trio's_path.pydefinestrio.Pathby wrapping every method ofpathlib.Path/PurePathvia a metaclass (AsyncAutoWrapperType.generate_forwards), iterating overpathlib.Path's class attributes.Python 3.13 added a new class attribute to
pathlib.PurePath:parser(a module reference, e.g.posixpath/ntpath, part of the new path-flavour abstraction). Older versions oftrio(e.g. 0.23.1) assume every wrapped attribute is callable/descriptor-like and blow up when it encounters a bare module:This exception propagates all the way up through
httpcore→httpx.Client.__init__→oikb._make_client(), wherecli.pycatches it as a genericExceptionand prints:Since the
TypeErrorwas raised with two positional args,str(e)renders asrepr(e.args)— hence the odd('parser', <class 'module'>)output, with zero indication that this is an import-time failure unrelated to networking.Fix on the user side:
pip install --upgrade trio(0.23.1 → 0.33.0 resolves it).Reproduction
On an affected environment (Python 3.13 + trio < ~0.26) this raises the traceback below instead of returning silently.
Full traceback
Suggested fixes for oikb
None of this is oikb's bug per se (it's an upstream
trio/Python 3.13 incompatibility), but oikb's error handling makes it very hard to diagnose. Suggestions, roughly in order of preference:_make_client()/ thevalidate --deephandler, catch import/construction errors fromhttpx.Client()separately and print the full exception type + traceback (or at leastrepr(e)instead ofstr(e)) so users can see it's aTypeErroron import, not a connection failure.httpcore's optionaltriobackend needs to be pulled in at all for oikb's use case (oikb only uses the synchttpx.Client, nothttpx.AsyncClient) — if there's a way to avoid triggering the trio import path for sync-only usage, that would sidestep this class of issue entirely.trioversion (or addtrio>=0.26as an explicit constraint) inpyproject.tomlifhttpcore/trioend up in the dependency tree on Windows, since oldertriois incompatible with Python 3.13.Additional notes
Direct connectivity to Open WebUI was confirmed working the whole time (
curl -i $OPEN_WEBUI_URL/healthreturned200 OK) whileoikb validate --deepreported "Cannot reach Open WebUI" — worth flagging explicitly in any fix/doc update that this message can be a false negative for network reachability.