n4nAI

Fix LlamaIndex connection errors with n4n.ai

Fix LlamaIndex connection errors when using n4n.ai as your LLM gateway with step-by-step troubleshooting and working code examples.

n4n Team4 min read871 words

Audio narration

Coming soon — every post will get a voice note here.

LlamaIndex connection errors n4n.ai tutorial searches spike every time a provider rolls out a breaking API change or a gateway updates its routing logic. Most of these failures boil down to three things: mismatched base URLs, incorrect authentication headers, or model identifiers that don’t exist on the target provider. This guide walks through the common failure modes, shows how to isolate the root cause, and gives you a working configuration you can drop into your project.

Step 1: Verify your environment and dependencies

Start with a clean virtual environment. Version conflicts between llama-index, openai, and httpx cause silent failures that look like network errors.

python -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install "llama-index>=0.10.0" "openai>=1.30.0" httpx

Confirm the versions you actually installed:

import llama_index
import openai
import httpx

print(f"llama-index: {llama_index.__version__}")
print(f"openai: {openai.__version__}")
print(f"httpx: {httpx.__version__}")

Verify success: You see version numbers printed without import errors. If llama-index shows a version below 0.10, upgrade — older releases don’t support the OpenAI-compatible client pattern cleanly.

Step 2: Isolate the connection with a minimal test

Strip away your application logic. Hit the gateway directly with the OpenAI Python client first. This tells you whether the problem is network, auth, or LlamaIndex wrapper code.

import os
from openai import OpenAI

client = OpenAI(
    api_key=os.getenv("N4N_API_KEY"),
    base_url="https://api.n4n.ai/v1",
    timeout=30.0,
    max_retries=2,
)

try:
    resp = client.chat.completions.create(
        model="meta-llama/llama-3.1-8b-instruct",
        messages=[{"role": "user", "content": "ping"}],
        max_tokens=5,
    )
    print("Raw client works:", resp.choices[0].message.content)
except Exception as e:
    print(f"Raw client failed: {type(e).__name__}: {e}")

Set N4N_API_KEY in your shell or .env file before running.

Verify success: You see Raw client works: pong (or similar). If this fails, the issue is credentials, network, or the model identifier — not LlamaIndex. Check the error type:

  • AuthenticationError → invalid or missing API key
  • NotFoundError → model identifier doesn’t exist on the gateway
  • APIConnectionError / Timeout → network, DNS, or firewall
  • RateLimitError → you hit a provider or gateway limit

Step 3: Map model identifiers correctly

The most common LlamaIndex connection errors n4n.ai tutorial readers hit involve model names. LlamaIndex’s OpenAILike class passes the model string straight to the gateway. If the gateway doesn’t recognize it, you get a 404 that surfaces as a generic connection error.

List available models programmatically:

import os
from openai import OpenAI

client = OpenAI(
    api_key=os.getenv("N4N_API_KEY"),
    base_url="https://api.n4n.ai/v1",
)

models = client.models.list()
for m in models.data:
    print(m.id)

Pick an exact ID from that list. Common mistakes:

  • Using llama-3.1-8b instead of meta-llama/llama-3.1-8b-instruct
  • Omitting the provider prefix (openai/, anthropic/, meta-llama/, etc.)
  • Using a display name from the dashboard instead of the API identifier

Step 4: Configure LlamaIndex with the OpenAILike LLM

Now wire it into LlamaIndex. Use OpenAILike — not OpenAI — because the gateway is OpenAI-compatible but not the OpenAI API itself.

import os
from llama_index.llms.openai_like import OpenAILike
from llama_index.core import Settings

llm = OpenAILike(
    model="meta-llama/llama-3.1-8b-instruct",
    api_key=os.getenv("N4N_API_KEY"),
    api_base="https://api.n4n.ai/v1",
    is_chat_model=True,
    temperature=0.1,
    max_tokens=512,
    timeout=30,
    max_retries=2,
    additional_kwargs={},  # pass provider-specific params here if needed
)

Settings.llm = llm

Verify success: Run a trivial completion through the LlamaIndex abstraction:

from llama_index.core.llms import ChatMessage

resp = llm.chat([ChatMessage(role="user", content="Say hello in one word.")])
print(resp.message.content)

You should see a one-word response. If this hangs or throws, check:

  • api_base includes /v1 (the gateway expects the full OpenAI-compatible path)
  • is_chat_model=True for chat models; set False for completion-only models
  • timeout and max_retries are set — defaults can hang indefinitely on degraded providers

Step 5: Handle embeddings separately

Embedding models often live on a different endpoint or require a different model identifier. Configure them explicitly rather than relying on Settings.embed_model defaults.

from llama_index.embeddings.openai_like import OpenAILikeEmbedding

embed_model = OpenAILikeEmbedding(
    model="nomic-ai/nomic-embed-text-v1.5",
    api_key=os.getenv("N4N_API_KEY"),
    api_base="https://api.n4n.ai/v1",
    timeout=30,
    max_retries=2,
)

Settings.embed_model = embed_model

Test it:

vec = embed_model.get_text_embedding("test")
print(f"Embedding dimension: {len(vec)}")

Verify success: You get a vector of the expected dimension (768 for nomic-embed-text-v1.5). If you get a 404, list embedding models the same way you listed chat models — the identifier differs.

Step 6: Enable request logging to see what actually goes over the wire

When things still fail, you need visibility. LlamaIndex uses the OpenAI client under the hood, which uses httpx. Patch httpx to log requests and responses.

import httpx
import logging

logging.basicConfig(level=logging.DEBUG)
httpx_logger = logging.getLogger("httpx")
httpx_logger.setLevel(logging.DEBUG)

# Or use a custom transport for structured logging
class LoggingTransport(httpx.BaseTransport):
    def __init__(self, wrapped):
        self.wrapped = wrapped

    def handle_request(self, request):
        print(f">>> {request.method} {request.url}")
        print(f">>> Headers: {dict(request.headers)}")
        if request.content:
            print(f">>> Body: {request.content.decode()[:500]}")
        response = self.wrapped.handle_request(request)
        print(f"<<< {response.status_code}")
        return response

# Apply to your OpenAI client
client = OpenAI(
    api_key=os.getenv("N4N_API_KEY"),
    base_url="https://api.n4n.ai/v1",
    http_client=httpx.Client(transport=LoggingTransport(httpx.HTTPTransport())),
)

Run your failing call again. You’ll see the exact request the gateway receives — including headers, model string, and payload — and the exact response code and body.

Step 7: Implement retry and fallback logic at the application layer

Gateway-level fallback handles provider degradation, but your code should still handle transient gateway errors (5xx, timeouts, rate limits). Wrap your LlamaIndex calls with tenacity.

from tenacity import (
    retry,
    stop_after_attempt,
    wait_exponential_jitter,
    retry_if_exception_type,
)
from openai import RateLimitError, APIConnectionError, InternalServerError

@retry(
    wait=wait_exponential_jitter(initial=1, max=30),
    stop=stop_after_attempt(3),
    retry=retry_if_exception_type((RateLimitError, APIConnectionError, InternalServerError)),
    reraise=True,
)
def safe_chat(messages):
    return llm.chat(messages)

# Usage
resp = safe_chat([ChatMessage(role="user", content="Explain RAG in two sentences.")])
print(resp.message.content)

Verify success: Simulate a failure by temporarily setting an invalid model name, then watch the retry logic kick in (check logs). Restore the correct model and confirm the call succeeds on first attempt.

Step 8: Validate the full pipeline with a real query

Now exercise the complete stack: embedding → retrieval → generation. This catches integration issues that unit tests miss.

from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings
from llama_index.core.node_parser import SentenceSplitter

# Re-use the configured Settings from Steps 4-5
# Settings.llm and Settings.embed_model already set

# Ingest a small test corpus
documents = SimpleDirectoryReader("./test_docs").load_data()
parser = SentenceSplitter(chunk_size=512, chunk_overlap=50)
nodes = parser.get_nodes_from_documents(documents)

index = VectorStoreIndex(nodes)
query_engine = index.as_query_engine(similarity_top_k=3)

response = query_engine.query("What is the main topic of these documents?")
print(response.response)
print("\n--- Sources ---")
for src in response.source_nodes:
    print(f"  Score: {src.score:.3f} | Text: {src.text[:100]}...")

Create ./test_docs/ with a few .txt files first.

Verify success: You get a coherent answer with source citations. If the query hangs, check:

  • Embedding model returns vectors (Step 5 test)
  • LLM returns completions (Step 4 test)
  • No silent truncation — max_tokens on the LLM is high enough for the answer

Step 9: Common error patterns and fixes

Error symptom Likely cause Fix
AuthenticationError on first call N4N_API_KEY not set or invalid Export key; verify in dashboard
NotFoundError: model not found Wrong model identifier List models (Step 3); use exact ID
APIConnectionError / timeout Network, firewall, or gateway overload Increase timeout; add retries; check egress
RateLimitError immediately Per-key or per-IP limit Back off; implement exponential backoff (Step 7)
Empty response / None content max_tokens too low or stop sequence triggered Raise max_tokens; check additional_kwargs
Embedding dimension mismatch Different embedding model at query vs index time Use same embed_model for ingestion and query
AttributeError: 'NoneType' object has no attribute 'chat' Settings.llm not set before index creation Set Settings.llm before building index

Step 10: Production hardening checklist

Before shipping, lock down these settings:

# Explicit timeouts everywhere
llm = OpenAILike(
    # ... other params ...
    timeout=60.0,           # generous for large contexts
    max_retries=3,
)

embed_model = OpenAILikeEmbedding(
    # ... other params ...
    timeout=30.0,
    max_retries=3,
)

# Structured logging for observability
import structlog
structlog.configure(
    processors=[
        structlog.processors.add_log_level,
        structlog.processors.TimeStamper(fmt="iso"),
        structlog.processors.JSONRenderer(),
    ]
)
logger = structlog.get_logger()

# Wrap query engine for logging
class LoggedQueryEngine:
    def __init__(self, engine):
        self.engine = engine

    def query(self, q):
        logger.info("query_start", query=q)
        try:
            resp = self.engine.query(q)
            logger.info("query_success", latency_ms=resp.metadata.get("latency_ms"))
            return resp
        except Exception as e:
            logger.error("query_failed", error=str(e), exc_info=True)
            raise

query_engine = LoggedQueryEngine(index.as_query_engine(similarity_top_k=5))

Verify success: Deploy to staging. Generate load. Confirm:

  • P99 latency within SLA
  • Error rate < 0.1% under normal load
  • Logs show request/response correlation IDs for tracing
  • Fallback behavior triggers cleanly when you simulate provider failure

You now have a working, observable LlamaIndex pipeline backed by an OpenAI-compatible gateway. The same pattern applies to any gateway that speaks the OpenAI wire format — swap the base_url and model identifiers, and the rest carries over.

Tagsllamaindexn4n-aitroubleshootingerrors

Written by

n4n Team

The team building n4n — a single OpenAI-compatible API in front of 240+ models, with automatic fallback, load balancing and pay-per-token metering.

More from n4n Team →

All llamaindex getting started with n4n.ai posts →