Skip to main content

cognee.validate()

Description

Cross-check the graph and vector stores of a dataset and report where they disagree. validate() answers three questions no other call answers: does every edge still point at nodes that exist, does every deduplicated node still carry the id its own dedup contract derives, and is every embeddable node actually present in its vector collection. The check is read-only β€” it never writes to any store, so it is safe to run against a production dataset. It is also backend-agnostic: it is driven entirely through GraphDBInterface.get_graph_data() and VectorDBInterface.retrieve(), so it works unmodified against every supported graph and vector backend without adapter-specific code. Run it after cognify(), after a large import, or after a migration β€” the moments when the graph and the vector index can drift apart.

Parameters

Optional[Union[str, List[str]]]
default:"'main_dataset'"
Dataset name(s) to validate. A single string is treated as a one-element list.
Optional[User]
default:"None"
User context for dataset access. Falls back to the default user.
Only one graph is checked per call: dataset is resolved to the datasets you have read permission on, and the first of those determines which graph and vector store are read. Passing several dataset names does not merge them into a combined report β€” call validate() once per dataset instead.
If none of the given names resolves to a dataset you can read, no dataset context is entered. With backend access control enabled (ENABLE_BACKEND_ACCESS_CONTROL=True, the default) that raises β€” a dataset is required to resolve the per-dataset databases. With access control disabled, the call falls back to the single shared graph and vector stores instead, so a typo in a dataset name yields a report about the default stores rather than an error. Check summary["graph_nodes"] before reading a healthy status as proof that a specific dataset is intact.

Returns

ValidationReport β€” a Pydantic model with three fields: status is derived from the severities present, not from issue counts:
  • any error-severity issue β†’ unhealthy
  • otherwise, any warning-severity issue β†’ degraded
  • no issues at all β†’ healthy
validate, ValidationReport, ValidationIssue, and ValidationStatus are importable from the cognee top level; the IssueSeverity and IssueType enums are available from cognee.api.v1.validate. All three enums (ValidationStatus, IssueSeverity, IssueType) subclass str, so comparing against plain strings (report.status == "healthy") works without importing them β€” but printing a member shows the enum repr (ValidationStatus.HEALTHY), so use .value when you want the plain string.

What is checked

An edge whose source or target id is not in the graph’s node set. Traversal that reaches such an edge hits a dead end, so graph-based search silently loses the connection.The detail names the edge as source -[relationship]-> target along with the id(s) that are missing. Typically the result of nodes being removed without their edges; re-running cognify() for the affected dataset, or deleting and re-ingesting the source data, rebuilds a consistent edge set.
A node of a type that declares identity_fields β€” Entity and EntityType, both keyed on name β€” whose id does not equal the id its own class derives from its properties via Type.id_for(...).Cognee’s dedup contract is that two nodes with the same identity value are the same node because they hash to the same id. A node that reached the graph without going through that contract (a raw write from an importer or a migration, or a node written by an older Cognee version) can carry a stale or arbitrary id β€” which means a second, correctly-derived node for the same entity can coexist as an undetected duplicate. Hence a warning rather than an error: nothing is broken yet, but deduplication is no longer guaranteed for that node.The check is skipped for a node whose identity field is absent from its graph properties β€” the id cannot be recomputed, and the node may simply predate the field. To bring mismatched nodes onto the current scheme, re-cognify the affected datasets from scratch so their ids are derived by the models.
A node of a type that declares index_fields β€” Entity (collection Entity_name) and DocumentChunk (collection DocumentChunk_text) β€” with no matching point in its {type}_{index_field} vector collection.The node exists in the graph but is unreachable by every embedding-based search type, silently: semantic search cannot surface it and cannot use it to seed graph traversal. Re-running cognify() for the dataset re-indexes the missing nodes. If an entire node type reports one issue per node, the collection itself is likely missing or empty rather than individual points having been lost.
The checked types are read from the real model classes’ identity_fields / index_fields metadata rather than being hardcoded, so a change to either contract is picked up here automatically.

Cost and when to run

  • No LLM calls and no writes. The cost is entirely database reads.
  • The graph is read in full through get_graph_data(), so time and memory scale with the total number of nodes and edges β€” not with a sample. There is no sampling or limit parameter.
  • Vector lookups are one batched retrieve() per collection (at most two: Entity_name and DocumentChunk_text), not one call per node.
  • Because it is read-only, it is safe against production stores β€” but on a very large dataset prefer a low-load window, and note that the number of issues is unbounded: a badly drifted graph can return one issue per affected node or edge.
Good moments to run it: after cognify() or a bulk import, after applying migrations, as a pre-flight check in CI, or on a schedule as integrity monitoring.

Examples

Acting on the status β€” for example, failing a CI pre-flight check on errors while letting warnings through:
Grouping issues by type to decide what to remediate:

Over HTTP

The same check is exposed as a read-only endpoint on the API server:
The 503 is the single detail to plan for when wiring this into a health probe or a CI check: an unhealthy report is returned with a 503 status code, not a 200. Clients that raise on non-2xx responses will treat a successful-but-failing validation as a transport error, and a load balancer pointed at this path will pull the instance out of rotation on a data-integrity finding. Read the response body to tell the two apart β€” a 503 from this endpoint still carries the full report JSON, while a 500 carries {"status": "error", "reason": ...}.

See also

  • report() β€” the other read-only diagnostic: what the graph contains, rather than whether it is consistent
  • cognify() β€” the pipeline that writes the nodes, edges, and vector points this call cross-checks
  • DataPoints β€” identity_fields, index_fields, and the id_for() contract the identity check verifies
  • run_startup_migrations() β€” apply pending schema migrations; validating afterwards confirms the stores still agree