#1893·graphiti

[BUG] import graphiti_core fails on a fresh install: No module named 'httpx' (openai>=3 depends on httpx2)

Author: daniellaahCreated Sep 17, 2026Updated Sep 17, 2026
Labelsbug

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 Graphiticross_encoderllm_clientclient.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

bash
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 and uv.lock bring httpx in 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>=3 hits it.
  • Component: core library (MCP server not affected, it ships its own uv.lock).
  • Affected install paths: bare pip install graphiti-core and graphiti-core[anthropic] (anthropic ≥1.6 has also moved to httpx2). Not affected: [groq], [google-genai], [dev], since those extras still depend on httpx.
  • Affected releases: at least 0.29.3 (2026-07-27) through 0.30.2 (2026-09-08).
  • httpx is only referenced in graphiti_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

Possible Solution

Option A (minimal, no dependency changes): make the import tolerant of either package in client.py:

python
try:
    import httpx
except ImportError:  # openai>=3 ships httpx2 instead of httpx
    import httpx2 as httpx

httpx2.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.