Skip to main content

Troubleshoot common errors

Find the message you see. Then follow the fix. The messages here come from Neo4j 5.26 and the driver version in the lock file. The exact text can differ slightly in other versions.

Neo4j rejects the login​

You see:

neo4j.exceptions.AuthError: {neo4j_code: Neo.ClientError.Security.Unauthorized} {message: The client is unauthorized due to authentication failure.}

The username or password does not match the server. Agentic GraphRAG reads NEO4J_USERNAME and NEO4J_PASSWORD. The default password is neo4j, so a server with another password fails.

  1. Set NEO4J_USERNAME and NEO4J_PASSWORD in your shell or in a .env file to the values of your server.
  2. Run this test. It prints connected when the login works.
import asyncio

from agrag.graphdb import build_graph_store


async def main() -> None:
graph_store = build_graph_store("neo4j")
await graph_store.connect()
print("connected")
await graph_store.close()


asyncio.run(main())

Neo4j is not reachable​

You see:

neo4j.exceptions.ServiceUnavailable: Couldn't connect to localhost:7699 (resolved to ('127.0.0.1:7699',)): Failed to establish connection ... [Errno 111] Connect call failed

Nothing accepts connections at NEO4J_URI. The server can be stopped, on another port, or still starting. A new Neo4j container needs about 30 seconds.

  1. Make sure that the server runs. For Docker, run docker ps.
  2. Make sure that NEO4J_URI names the right host and port. The default is bolt://localhost:7687.
  3. Run the test from the previous section until it prints connected.

Agentic GraphRAG refuses the Neo4j address​

You see:

Value error, 'bolt://db.example.com:7687' uses an unencrypted scheme ('bolt') but sends a configured credential to a non-local host; use one of ['bolt+s', 'bolt+ssc', 'neo4j+s', 'neo4j+ssc'] instead

Agentic GraphRAG does not send a password over an unencrypted connection to a remote host. Use an encrypted scheme. Aura addresses use neo4j+s://.

export NEO4J_URI="neo4j+s://<your-instance>.databases.neo4j.io"

The same rule applies to Qdrant, Weaviate, and Milvus when an API key or token is set. Use an https address for a remote server.

A later add fails after you deleted data by hand​

You see:

GraphStoreAliasConflictError: merge_key alias already claimed by another entity: {'<label>:<name>': '<id>'}

Agentic GraphRAG keeps bookkeeping nodes beside the graph, such as merge aliases and document jobs. If you delete only the entity and chunk nodes, the bookkeeping points at entities that no longer exist.

To start over, delete every node in the database and drop the vector indexes. This removes all data in the database, so use it only when the database holds nothing but Agentic GraphRAG data. See the last section for the commands.

A package extra is missing​

The message names the extra to install. The command in the message is correct.

You seeInstall
GraphStoreMissingExtraError: needs the 'neo4j' extraneo4j
EmbeddingMissingExtraError: needs the 'embed-local' extraembed-local
ExtractorMissingExtraError: 'GlinerExtractor' needs the 'extract' extraextract
ExtractorMissingExtraError: 'BAMLExtractor' needs the 'llm' extrallm
VectorStoreMissingExtraError: needs the 'qdrant' extraqdrant, weaviate, or milvus
AgentMissingExtraError: needs the 'observability' extraobservability
MissingExtraError: '.pdf' needs the 'docling' extradocling
The 'docling' chunker needs the 'docling' extradocling

Install an extra with uv pip install "agentic-graphrag[<extra>]".

A source with a missing loader extra follows your error policy. With SKIP, Agentic GraphRAG skips the file. With QUARANTINE, Agentic GraphRAG sets it aside and reports it. With RAISE, the run stops.

note

Without the agents extra, build_agent raises no error. It returns a simple agent that runs one search and writes one answer. Install agents to get the planner, researcher, and verifier.

The schema is rejected​

You see one of these:

Value error, Relation 'TREATS' pattern target 'Condition' is not a declared entity
Value error, Entity type 'Drug' declares reserved property name(s) ['text']; ['label', 'text'] are vector payload keys used for retrieval filtering and keyword search. Rename or remove those property names in the schema.

Every relation pattern must name entity types that the schema declares. An entity property cannot be named label or text.

Declare each entity type, then write the pattern. This schema passes:

from agrag.common.data_models import EntityType, GraphSchema, RelationType

schema = GraphSchema(
name="medicine",
version="1",
entities=[
EntityType(label="Drug", description="A medicine."),
EntityType(label="Condition", description="A disease or symptom."),
],
relations=[
RelationType(
label="TREATS",
description="A drug treats a condition.",
patterns=[("Drug", "Condition")],
)
],
)
print(schema.name, [entity.label for entity in schema.entities])

A search returns nothing​

A search that finds nothing raises no error in most cases. These are the causes, from most to least common.

The engine uses a different schema than the graph. SearchEngine searches the entity indexes of one schema. Without graph_schema, it uses the generic schema. A graph opened with another schema then returns no entities. Pass the same schema to Graph.open and to SearchEngine:

import asyncio

from agrag.common.data_models import GENERIC
from agrag.embedding import build_embedder
from agrag.graphdb import build_graph_store
from agrag.ingestion import GlinerExtractor, Graph
from agrag.retrieval import ENTITY, SearchEngine


async def main() -> None:
embedder = build_embedder("ibm-granite/granite-embedding-small-english-r2")
graph_store = build_graph_store("neo4j")
graph = await Graph.open(
schema=GENERIC,
graph_store=graph_store,
embedder=embedder,
extractor=GlinerExtractor(),
)
await graph.add(text="Grace Hopper worked at Harvard on the Mark I computer.")
engine = SearchEngine(
graph_store=graph_store, embedder=embedder, graph_schema=GENERIC
)
results = await engine.search("Grace Hopper", ENTITY)
print(len(results))
await graph_store.close()


asyncio.run(main())

A filter matches nothing. SearchFilters(document_ids=[...]) keeps only results from those documents. An id that no ingested document has gives an empty list. Make sure that each id names an ingested document.

The vector index does not exist. A search in the Neo4j vector indexes returns no hits when the index is missing. Before you search, open the graph once. Graph.open creates the indexes.

The vector store has no collections for this graph. With a vector store on the engine, you can see:

AllRetrievalMethodsFailedError: every retrieval method failed: entity: UnexpectedResponse(); chunk: UnexpectedResponse()

Only Graph.open(vector_store=...) creates the collections. Open the graph with the same vector store and ingest your documents.

The engine uses another embedder than the graph. A query vector of another size makes each Neo4j vector search fail, so search raises AllRetrievalMethodsFailedError instead of returning results. Pass SearchEngine the embedder that you pass to Graph.open. To change the model of the graph, see the next section.

The simple agent answers No relevant evidence found. when a search returns nothing.

The embedding dimension does not match​

Graph.open compares the dimension of your embedder with the vector indexes and collections that already exist. When they differ, it raises one of these errors:

EmbeddingDimensionMismatchError: expected dimension 384, embedder produces 4
CollectionDimensionMismatchError: collection expects dimension 384, but 4 was requested

The first error comes from a Neo4j vector index. The second error comes from a vector store collection. Both errors mean that the stored vectors come from a model that makes 384 values, and your embedder makes 4.

  1. To keep your data, open the graph with the original embedder.
  2. To change models, start with an empty database and empty collections. This deletes all data in the database. Then open the graph with the new embedder and ingest your documents again.
await graph_store.execute_write("MATCH (n) DETACH DELETE n")
indexes = await graph_store.execute_read(
"SHOW INDEXES YIELD name, type WHERE type = 'VECTOR' RETURN name"
)
for row in indexes:
await graph_store.execute_write(f"DROP INDEX `{row['name']}` IF EXISTS")