[BUG] import graphiti_core fails on a fresh install: No module named 'httpx' (openai>=3 depends on httpx2)
Bug Description
import graphiti_core fails on a fresh install with ModuleNotFoundError: No module named 'httpx'.
graphiti_core/llm_client/client.py does a top-level import httpx, but httpx is not a declared dependency of graphiti-core. It used to arrive transitively through openai<3. Since openai 3.0.0 (released 2026-08-12) the SDK depends on httpx2 instead of httpx, and pyproject.toml only pins openai>=1.91.0 with no upper bound, so a fresh install now resolves openai 3.x, httpx is never installed, and the package fails at import time. Because graphiti_core/__init__.py imports Graphiti → cross_encoder → llm_client → client.py, this breaks every import graphiti_core, regardless of which LLM provider or database backend the user intends to use.
CI does not catch this because it installs from uv.lock, which still pins openai==2.32.0 (and httpx==0.28.1). The dev extra also pulls in groq and google-genai, which still depend on httpx, so development environments get it by accident.
Steps to Reproduce
uv venv -p 3.12 /tmp/g && VIRTUAL_ENV=/tmp/g uv pip install graphiti-core
/tmp/g/bin/python -c "import graphiti_core"Expected Behavior
import graphiti_core succeeds.
Actual Behavior
ModuleNotFoundError: No module named 'httpx' (see traceback below).
Environment
- Graphiti Version: 0.30.2 (PyPI); also reproduces on
main@c035afb - Python Version: 3.12.12
- Operating System: macOS 26.6.2 (Darwin 25.6)
- Database Backend: N/A (fails before any driver is touched)
- LLM Provider & Model: N/A (fails at import)
Installation Method
- pip install
- uv add
- Development installation (git clone) — not affected, because
[dev]extras anduv.lockbringhttpxin transitively
Error Messages/Traceback
Traceback (most recent call last):
File "<string>", line 1, in <module>
File ".../site-packages/graphiti_core/__init__.py", line 1, in <module>
from .graphiti import Graphiti
File ".../site-packages/graphiti_core/graphiti.py", line 26, in <module>
from graphiti_core.cross_encoder.client import CrossEncoderClient
File ".../site-packages/graphiti_core/cross_encoder/__init__.py", line 18, in <module>
from .openai_reranker_client import OpenAIRerankerClient
File ".../site-packages/graphiti_core/cross_encoder/openai_reranker_client.py", line 25, in <module>
from ..llm_client import LLMConfig, OpenAIClient, RateLimitError
File ".../site-packages/graphiti_core/llm_client/__init__.py", line 17, in <module>
from .client import LLMClient
File ".../site-packages/graphiti_core/llm_client/client.py", line 23, in <module>
import httpx
ModuleNotFoundError: No module named 'httpx'Configuration
N/A — the failure is on import graphiti_core, before any configuration.
Additional Context
- Every fresh install that resolves
openai>=3hits it. - Component: core library (MCP server not affected, it ships its own uv.lock).
- Affected install paths: bare
pip install graphiti-coreandgraphiti-core[anthropic](anthropic≥1.6 has also moved tohttpx2). Not affected:[groq],[google-genai],[dev], since those extras still depend onhttpx. - Affected releases: at least 0.29.3 (2026-07-27) through 0.30.2 (2026-09-08).
httpxis only referenced ingraphiti_core/llm_client/client.py:- L23
import httpx - L71
isinstance(exception, httpx.HTTPStatusError) and 500 <= exception.response.status_code < 600(tenacity retry predicate) - L140
except (httpx.HTTPStatusError, RateLimitError) as e: raise e
- L23
Possible Solution
Option A (minimal, no dependency changes): make the import tolerant of either package in client.py:
try:
import httpx
except ImportError: # openai>=3 ships httpx2 instead of httpx
import httpx2 as httpxhttpx2.HTTPStatusError has the same .response.status_code shape, so the retry predicate and the except clause keep working unchanged.
Option B: declare httpx>=0.28 in [project.dependencies]. This also unbreaks the import, but note that the retry predicate then checks httpx.HTTPStatusError while openai 3.x is built on httpx2. In practice this branch is already unreachable for the OpenAI clients (the SDK wraps HTTP errors in openai.APIStatusError and never surfaces raw httpx exceptions; openai_base_client.py:300 already retries on openai.InternalServerError separately), so the impact is limited to third-party LLMClient subclasses that raise raw HTTPStatusError.
Option C (cleaner long term): drop the httpx reference from client.py entirely and express the retry predicate in terms of SDK-level exceptions.
I'd suggest Option A as the least invasive fix and am happy to open a PR for it, but I'm equally fine implementing B or C if you'd prefer — let me know.
Source: getzep/graphiti