For AI agents: this page is also available as Markdown at /docs/graph.md. Every docs page is: add .md to its URL. llms.txt lists them all.

Graph search

Graph search queries a knowledge graph stored in an ordinary collection. Most graph retrieval is a few hops from a handful of seed entities: find the entities a question is about, walk to their neighbors, score what you reached by how close it is to the seeds, and fetch the passages that mention them. WarpSearch does this inside one collection, in one request, against one consistent snapshot, with the same filters, facets and vector search as any other search.

Feature What it does
lookup A query that selects documents by the values another query's matches hold (a semi-join). Covers one hop, reverse edges, and ACLs read from a user's document.
Graph expand Bounded multi-hop expansion with scoring: up to 3 hops over adjacency fields or edge documents, ranked by spreading activation or personalized PageRank, with facets and searches over the neighborhood, the traversed edges as a subgraph, and a size budget for prompt context.
Graph paths Shortest and k-shortest paths between sets of entities, or every path in a length range, with the edges that link them as evidence.

Modeling a graph

A graph lives in an ordinary collection. A node is a document, identified by its id. Edges come in two forms, and you can use both in one collection and mix them in one request.

Adjacency fields

The simplest edge is a multi-valued string field on the node that holds neighbor ids:

{"id": "svc-pay", "kind_s": "entity", "type_s": "service", "name_t": "Payments Service",
 "aliases_ss": ["payments", "pay-svc"], "related_ss": ["team-core", "svc-ledger"],
 "ancestors_ss": ["org", "eng", "platform"], "pagerank_f": 0.9, "acl_ss": ["eng"],
 "embedding_v": [0.12, 0.98, 0.04]}
{"id": "ch1", "kind_s": "chunk", "text_t": "payments outage postmortem",
 "mentions_ss": ["svc-pay", "team-core"], "acl_ss": ["eng"]}

Edge documents

When an edge needs a type, a weight, a validity window or provenance, store one document per edge:

{"id": "e1", "kind_s": "edge", "src_s": "alice", "dst_s": "svc-pay", "type_s": "WORKS_ON",
 "weight_f": 0.9, "source_chunk_s": "ch7", "valid_from_dt": "2024-01-01", "valid_to_dt": "2030-01-01"}

src_s and dst_s hold node ids (rename them per request), the weight is any numeric field, and any other field can be filtered on or returned as evidence. Edge and node documents can share the collection, told apart by a field such as kind_s.

Which to use

Adjacency field Edge documents
Storage One field per relation on the node One document per edge
Edge type One field per type (works_on_ss, owns_ss) A field on the edge, filterable
Weight None (every edge counts 1) Any numeric field
Validity, ACL, provenance No Yes, as filters and returned fields
Fan-out cap First values of the field Heaviest edges first
Best for Entity links, mentions, hierarchies Extracted relations, temporal facts, cited links

Two more modeling patterns need no graph feature at all:

lookup: one hop as a query

lookup selects the documents whose field holds any value of from_field across the documents matching from. It is a query in the native warpsearch language, usable in query or filters, combined with AND, or nested inside another lookup. Native expressions run unsigned on dedicated collections without row filters or field restrictions; on restricted collections, replay a signed translation (see Query languages).

{"language": "warpsearch",
 "query": "lookup(id, from=id:=$seed, from_field=related_ss)",
 "vars": {"seed": "svc-pay"}}
Parameter Meaning
field The field to match on.
from The query whose matches supply the values. Put values in vars.
from_field The field whose values those matches hold.
max_values Cap on the distinct values (default 65536). Exceeding it is an error.
Use Setting Result
Outbound neighbors field: id, from_field: related_ss The entities svc-pay points at.
Inbound neighbors field: related_ss, from_field: id The entities pointing at the seeds.
ACLs from the user's document field: acl_ss, from: id:=$user, from_field: groups_ss The documents visible to any of the user's groups.
Two hops A lookup nested in from For example "everyone working on the projects Alice works on", or a group-of-groups closure.

Both fields are string-valued (keyword and id fields) or both integer-valued (integer and date fields). The values come from the same snapshot as the rest of the search, and the inner query sees every live document, not the request's other filters. A repeated lookup, such as the same user's ACL filter on every search, is cached as one entry however many values it resolves.

Graph expand

POST /v1/collections/{collection}/graph/expand starts from seed documents, follows up to 3 hops, scores every node it reaches and returns them best first:

curl -s https://api.warpsearch.io/v1/collections/kg/graph/expand \
  -H "Authorization: Bearer $WARPSEARCH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "seeds": {"query": "name_t:\"payments outage\"", "limit": 20},
    "hops": [
      {"field": "related_ss", "direction": "out", "decay": 0.5,
       "max_per_node": 25, "max_frontier": 500, "filter": "type_s:(service OR team)"},
      {"field": "mentions_ss", "direction": "in", "filter": "kind_s:chunk"}
    ],
    "propagate": "sum",
    "limit": 50,
    "fields": ["id", "name_t", "type_s"],
    "facets": {"types": {"field": "type_s"}}
  }'
{"took_ms": 6, "collection": "kg", "total": 31,
 "hits": [
   {"id": "svc-pay", "score": 7.2, "hop": 0, "fields": {"name_t": "Payments Service", "type_s": "service"}},
   {"id": "team-core", "score": 3.6, "hop": 1, "via": "svc-pay", "fields": {"name_t": "Core Team", "type_s": "team"}},
   {"id": "ch1", "score": 2.1, "hop": 2, "via": "team-core", "fields": {}}
 ],
 "facets": {"types": {"buckets": [{"val": "service", "count": 9}, {"val": "team", "count": 4}]}}}

How it works

  1. seeds is a search, or a list of node ids. Its matches start the walk, and their search scores are their starting scores (ids start at 1, or at the group's weight). Use any query, including a kNN search over entity names ("language": "es" with an ES knn body), or several weighted groups combined into one ranked list.
  2. Each hop expands the nodes the previous hop reached for the first time. A node is reached once, at its first hop, and is never revisited, so the walk cannot loop.
  3. A node's score is the sum (or, with "propagate": "max", the best) over the nodes that reached it of their score x decay x edge weight. Adjacency edges weigh 1. With the default sum, a node many seeds point at outranks one reached once.
  4. Every hop can cap its work: how many edges each node may follow, how many new nodes survive the hop, and which hubs are too connected to expand.
  5. The reached nodes come back best first, seeds included unless you exclude them, each with how many hops away it is and which node reached it. total counts every node reached, and facets and search run over all of them, not just the returned page. min_hop hides the nodes nearer than that (from hits, total, facets and search) while they still take part in the walk and the scores; include_seeds: false is min_hop: 1 for the seeds alone.

Request

Field Meaning
seeds The seed search: query, language, filters, limit (default 10), sort; or ids, a list of node ids. Or an array of up to 10 such groups, each with a weight (default 1) multiplying its scores; the group limits add up. sort is rejected with ids or weight. For vector seeds use "language": "es" and an ES knn search body as query.
hops Up to 3 hop objects, applied in order (below).
propagate sum (default) or max.
rank spread (default, the scores above) or ppr (personalized PageRank, below).
ppr PageRank options: alpha (damping, the probability of continuing the walk rather than restarting at a seed; default 0.5, HippoRAG's value; the web-graph 0.85 spreads much wider), iterations (default 50), tolerance (default 1e-6), undirected (default true), reset_field (a numeric field scaling each seed's restart weight, below).
limit How many nodes to return (default 10; -1 for your plan's maximum).
include_seeds Return the seeds too (default true).
min_hop Hide nodes nearer than this many hops (0 to the number of hops) from the hits, total, facets and search. They still traverse and score.
fields The fields to return for each node.
scores Return scores (default true).
edges true returns, with each node, the edge that reached it (below).
subgraph true returns every traversed edge of the reached subgraph under edges in the response (below), at most max_edges of them (default and maximum 100000; traversing more is a 429).
budget {"nodes", "edges", "edge_cost"}: keep a connected subgraph of bounded size around the seeds before ranking (below). At least one key.
timeout_ms Wall-clock budget, counted from the seed search. Once spent, no further hop runs, PPR stops where it is, and what was reached so far comes back with "timed_out": true.
filters Restrict every node the walk may reach, seeds included, for example an ACL or a tenant filter.
facets, metrics Analytics over every reached node. Same syntax as Facets and aggregations.
search A second search restricted to the reached nodes: query, language, filters, limit, fields, sort (kNN through "language": "es"). Returned as search.
max_nodes Safety cap on nodes reached (default and maximum 100000). Exceeding it is a 429.

A hop over an adjacency field:

Field Meaning
field The adjacency field.
direction out (default: the node's own values), in (nodes whose field holds this node's id) or both.
filter Which reached nodes to keep: an expression or an array that must all match.
decay Score multiplier for this hop (default 1).
max_per_node Follow at most this many edges from each node.
max_frontier Keep only the best-scored new nodes after the hop.
max_degree Do not expand nodes with more edges than this (hubs).

A hop over edge documents replaces field with edges:

{"edges": {"src": "src_s", "dst": "dst_s", "weight": "weight_f",
           "filter": ["type_s:WORKS_ON", "valid_from_dt:<=2025-06-01", "valid_to_dt:>=2025-06-01"],
           "fields": ["source_chunk_s", "type_s"]},
 "direction": "out", "max_per_node": 20, "decay": 0.5}
edges field Meaning
src, dst The fields holding the edge's endpoint ids (default src_s and dst_s). out follows src to dst, in dst to src.
weight A numeric field multiplied into the score. max_per_node keeps each node's heaviest edges.
filter Which edge documents count: edge type, validity at a point in time, ACL.
fields Edge fields returned as evidence with "edges": true.

Results

Each hit has the usual id, score and fields, and:

Field Meaning
hop 0 for a seed, else the hop that first reached the node.
via The id of the node that contributed most to its score. Absent on seeds.
edge With "edges": true: the link from via. For an edge document, {"id", "weight", ...requested fields}; for an adjacency field, {"field": "related_ss"}.

Following via back to a seed shows why a node was returned, and edge cites where the link came from, for example the passage it was extracted from.

The response also carries timed_out (true when timeout_ms cut the walk short) and, with "rank": "ppr", ppr: {"ran_iterations", "converged"}.

The whole subgraph

"subgraph": true adds edges to the response: every edge the walk traversed, in traversal order, each physical edge once even when both ends reached it. An edge is {"from", "to", "via", "weight", "hop"} plus, for an edge document, its id and the requested evidence fields; from and to are in the stored direction (the node holding the adjacency value to the value, or src to dst), via is the adjacency field or edges, and hop is the hop that traversed it. Edges to nodes hidden by include_seeds or min_hop are included; edges to nodes dropped by max_frontier are not. max_edges bounds the list.

A size budget

limit keeps the best nodes, which need not connect to each other or to the seeds. budget keeps a connected subgraph instead, before ranking and before anything is returned: starting from the seeds, it repeatedly adds the best-scored node adjacent to the kept set (attached by its heaviest edge) while at most nodes nodes and edges edges are kept and the node scores more than edge_cost (default 0); any edge budget left over takes the heaviest remaining edges among the kept nodes. The choice is greedy, not optimal, and with several seeds the result is a forest whose trees join where the neighborhoods meet. The hits, total, facets, search and the subgraph edges all cover the kept subgraph only; via and edge name the edge that attached each node. Seeds count toward nodes even when hidden.

Personalized PageRank

With "rank": "ppr", WarpSearch first collects the subgraph the hops reach, then ranks it by personalized PageRank: a random walk that follows edges (weighted by edge weight) and restarts at the seeds in proportion to their scores. Scores sum to 1 over the reached nodes. PPR favors nodes that are well connected to several seeds over nodes that are merely close to one; HippoRAG uses it for multi-hop question answering. hop and via are reported as before, and ppr in the response reports the iterations run and whether the last one moved less than tolerance.

ppr.reset_field names a numeric field whose value multiplies each seed's restart weight (HippoRAG's node specificity: a phrase node weighted by the inverse of the number of passages it occurs in). A seed without a value keeps its weight, a negative value counts as 0, and when every weight is 0 the restart is uniform over the seeds.

Recipe: GraphRAG passage retrieval

Find the entities a question names, walk to related entities and to the passages that mention them, and rank the passages:

{"seeds": {"query": "aliases_ss:(ledger OR payments)", "limit": 10},
 "hops": [{"field": "related_ss", "direction": "both", "max_degree": 1000},
          {"field": "mentions_ss", "direction": "in", "filter": "kind_s:chunk"}],
 "rank": "ppr",
 "include_seeds": false,
 "filters": ["acl_ss:(eng OR all-staff)"],
 "fields": ["id", "text_t"],
 "limit": 20}

Feed the returned passages, with their via chains as context, to your model.

Recipe: weighted seed groups

HippoRAG 2 seeds the walk with the entities an LLM confirmed, plus the passages a vector search found at a small weight. Both are one seeds array; ids need no query escaping:

{"seeds": [{"ids": ["ent:ledger", "ent:payments"]},
           {"language": "es", "query": {"knn": {"field": "embedding_v", "query_vector": [0.1, 0.9, 0.0], "k": 5}},
            "filters": [{"term": {"kind_s": "chunk"}}], "weight": 0.05}],
 "hops": [{"field": "related_ss", "direction": "both"},
          {"field": "mentions_ss", "direction": "in", "filter": "kind_s:chunk"}],
 "rank": "ppr", "include_seeds": false, "limit": 20}

The same form continues a walk from the ids a previous call returned, after your model picked the ones worth following.

Recipe: vector search inside a neighborhood

Restrict a kNN search to the graph around the seeds. The restriction applies inside the vector search, so recall holds:

{"seeds": {"ids": ["svc-pay"]},
 "hops": [{"field": "related_ss", "direction": "both"}],
 "limit": 0,
 "search": {"language": "es",
            "query": {"knn": {"field": "embedding_v", "query_vector": [0.1, 0.9, 0.0], "k": 5}},
            "fields": ["id", "name_t"]}}

For one hop, the same works on /v1/search with a lookup filter.

Recipe: the subgraph for visualization or triple lists

A client that draws the neighborhood, or a retriever that feeds an LLM a list of triples (SubgraphRAG and G-Retriever style), needs the edges, not only the nodes. subgraph returns every traversed edge, with edge-document evidence, beside the hits:

{"seeds": {"ids": ["svc-pay"]},
 "hops": [{"field": "related_ss", "direction": "both"},
          {"edges": {"weight": "weight_f", "filter": "kind_s:edge", "fields": ["type_s"]}, "direction": "both"}],
 "subgraph": true, "max_edges": 2000,
 "fields": ["id", "name_t"], "limit": -1}

Each edges entry has from, to, via, weight and hop, plus id and type_s for the edge documents, so (from, type_s, to) is a triple and the hits supply the node labels.

Recipe: token-bounded context with budget

For a prompt that can hold about thirty nodes, ask for the best connected thirty rather than the best thirty: budget grows a subgraph from the seeds by score and stops at the caps, so every returned node links back to a seed through returned nodes.

{"seeds": {"query": "aliases_ss:(ledger OR payments)", "limit": 5},
 "hops": [{"field": "related_ss", "direction": "both"},
          {"field": "mentions_ss", "direction": "in", "filter": "kind_s:chunk"}],
 "rank": "ppr",
 "budget": {"nodes": 30, "edges": 40},
 "subgraph": true, "fields": ["id", "name_t", "text_t"], "limit": -1}

The choice is greedy; with several seeds whose neighborhoods do not meet, the result is a forest.

Recipe: HippoRAG node specificity with reset_field

HippoRAG weights each seed phrase by its specificity (the inverse of how many passages mention it), so a rare entity pulls the walk more than a common one. Store it on the node and name it in ppr.reset_field; the field goes through the same alias and allow-list resolution as any other.

{"seeds": {"query": "aliases_ss:(ledger OR payments)", "limit": 10},
 "hops": [{"field": "related_ss", "direction": "both"},
          {"field": "mentions_ss", "direction": "in", "filter": "kind_s:chunk"}],
 "rank": "ppr", "ppr": {"alpha": 0.5, "reset_field": "specificity_f"},
 "min_hop": 2, "fields": ["id", "text_t"], "limit": 20}

min_hop: 2 returns only the passages; the seeds and the related entities still shape the PageRank. The response's ppr says how many iterations ran and whether they converged.

Graph paths

POST /v1/collections/{collection}/graph/paths finds how entities are connected:

curl -s https://api.warpsearch.io/v1/collections/kg/graph/paths \
  -H "Authorization: Bearer $WARPSEARCH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "alice", "to": ["svc-pay", "svc-ledger"],
    "edges": [
      {"field": "related_ss"},
      {"edges": {"weight": "weight_f", "filter": "type_s:(WORKS_ON OR OWNS)", "fields": ["source_chunk_s"]}}
    ],
    "max_depth": 4, "k": 3,
    "fields": ["name_t"]
  }'
{"took_ms": 3, "collection": "kg",
 "paths": [
   {"nodes": ["alice", "svc-pay"], "length": 1, "cost": 1,
    "edges": [{"from": "alice", "to": "svc-pay", "via": "edges", "id": "e1", "weight": 0.9, "source_chunk_s": "ch7"}]},
   {"nodes": ["alice", "team-core", "svc-pay"], "length": 2, "cost": 2,
    "edges": [{"from": "alice", "to": "team-core", "via": "related_ss"},
              {"from": "team-core", "to": "svc-pay", "via": "related_ss"}]},
   {"nodes": ["alice", "team-core", "svc-ledger"], "length": 2, "cost": 2,
    "edges": [{"from": "alice", "to": "team-core", "via": "related_ss"},
              {"from": "team-core", "to": "svc-ledger", "via": "related_ss"}]}
 ],
 "documents": {"alice": {"name_t": "Alice"}, "team-core": {"name_t": "Core Team"},
               "svc-pay": {"name_t": "Payments Service"}, "svc-ledger": {"name_t": "Ledger Service"}},
 "truncated": false, "timed_out": false, "explored": 23}
Field Meaning
from, to A node id, or up to 10 ids each. The search runs from the whole from set to the whole to set in one call and returns the best k paths overall, not k per pair (sorted by cost, then length). Duplicate ids are ignored, a missing node is skipped, and a node in both sets is a zero-length path.
edges The edge kinds to walk: adjacency hops and edge-document hops, as in graph expand. Undirected unless a spec sets "direction": "out" or "in". decay and max_per_node are rejected here. A spec's own max_frontier caps the new nodes that spec may add to one level, so a high fan-out edge type (chunk mentions) cannot crowd out the others.
max_depth Longest path, in edges (default 4, at most 6).
k How many paths (default 1, at most 10): the shortest, then the next shortest without repeating one.
weighted Rank by the sum of -log(weight) instead of the number of edges, so strong links win over short weak ones.
mode shortest (default) or all: every simple path from a from node to a to node with min_depth to max_depth edges, shortest first and by node ids within a length; cost is the length. k and weighted are rejected with it.
min_depth mode: "all" only: shortest path length to include (default 1; 0 to max_depth).
max_paths mode: "all" only: how many paths to return (default 100, at most 10000).
max_frontier Cap on nodes per exploration level (default 1000).
max_degree Do not expand hubs with more edges than this.
timeout_ms Wall-clock budget. Once spent, the exploration stops and the paths found over what was explored come back with "timed_out": true.
filters Restrict the nodes a path may pass through, for example to what the caller may see.
fields Fields of every node on a returned path, under documents keyed by id, so names and titles need no second request. Nodes you may not read are absent.

Each path lists its nodes in order and each edge it uses: via names the adjacency field or edges, and edge documents add their id, weight and requested fields as evidence. The search explores from both ends at once and stops when they meet (for one unweighted path) or at max_depth; in mode: "all" it explores to the full depth. A node past a frontier or degree cap is still reached, so it can end or join a path, but it is not expanded. truncated: true means a work cap cut the exploration short (a frontier or node cap, more than max_paths paths in mode: "all", or its internal cap on path prefixes), so a path may exist beyond it; timed_out: true means the same for timeout_ms. explored counts the nodes explored. The path search is one engine call and fields one more; a plan allows 20 per request.

Recipe: all paths between two entities up to length 3

To list how two entities are related rather than only the closest link, ask for every simple path in a length range. The paths come shortest first, so the first ones are the direct links and the later ones the indirect ones.

{"from": "svc-pay", "to": "team-core",
 "edges": [{"field": "related_ss"}, {"field": "mentions_ss"}],
 "mode": "all", "min_depth": 1, "max_depth": 3, "max_paths": 200,
 "fields": ["name_t"]}

truncated: true means more than max_paths paths exist; raise it (up to 10000), narrow the edge specs with a filter, or lower max_depth.

Many graph questions need no graph endpoint. All of these run on /v1/search:

Question Request
Who points at team-core? filters: ["related_ss:team-core"]
Everything under platform filters: ["ancestors_ss:platform"]
Head count per org facets: {"orgs": {"field": "ancestors_ss"}} over people
A seed's neighbors, as ids with counts facets: {"neighbors": {"field": "related_ss", "limit": -1}} over the seeds
A seed's neighbors, as documents query: "lookup(id, from=id:=$seed, from_field=related_ss)" (warpsearch, vars: {"seed": "svc-pay"})
Passages that mention an entity filters: ["mentions_ss:svc-pay"]
Which entities a set of passages mention facets: {"mentioned": {"field": "mentions_ss"}} over the passages
Rank entities by importance a rescore with score * log1p(pagerank_f)
Facts valid on a date filters: ["valid_from_dt:<=2025-06-01", "valid_to_dt:>=2025-06-01"]
Resolve an entity name RRF over fuzzy aliases_ss, exact aliases and a name embedding, see Hybrid search

Access control

Graph requests follow the collection's access control like any search: row filters and field restrictions apply to every node a walk or a path may reach. A node the caller cannot see is not returned, not counted in total or facets, and not used as a step toward other nodes. For document-level permissions, store the allowed groups on each document (acl_ss) and filter with a lookup from the user's document; the filter stays small and cached however many groups the user has.

MCP tools

Agents get three read-role tools over the same operations (see Agents). describe_collection first shows the adjacency fields.

Tool Arguments Returns
graph_neighbors collection; ids or query (+ language); field or edges (src, dst, weight, filter, fields); direction (default both); depth 1 to 3 (default 1); limit (default 20); min_hop (for example 2 with depth 2 keeps only second-degree nodes); filter; fields; rank (spread or ppr) nodes (id, score, hop, via, fields, edge), total, truncated (more nodes were reached than returned). Seeds are excluded.
graph_paths collection; from and to (arrays of 1 to 10 ids; the best k paths over all pairs); field or edges; direction; max_depth; k; weighted; mode (shortest or all); min_depth and max_paths (mode all); filter; fields paths, documents, truncated, timed_out, explored, as above.
graph_expand collection and request, the full expand request as JSON text The expand response. For weighted seed groups, per-hop decay and caps, min_hop, the full edge list (subgraph), a size budget, ppr.reset_field, timeout_ms, facets, metrics and a search inside the neighborhood.

Every tool description links this guide, so an agent that only has the tool list can find the request shapes. Clause arguments are strings in the tool's language (Lucene by default; ES clauses are JSON objects as text). For example, the people who exchanged mail with a person in the Enron demo:

{"collection": "enron", "ids": ["person:jeff.skilling@enron.com"],
 "field": "participant_ids_ss", "direction": "in", "filter": "kind:email", "limit": 20}

Limits

Limit Value
Hops per graph expand 3
Path depth 6 edges
Paths per request (k) 10
Nodes reached per request (max_nodes), edges returned with subgraph (max_edges), and an explicit max_frontier 100000 by default
Paths per request in mode: "all" (max_paths) 10000
Seed groups, and from or to ids per side 10
Engine calls per request (the path search, plus one for path fields) 20
PPR iterations 1000
Seeds, returned nodes and the nested search Your plan's max_limit; seed ids count as query clauses
Distinct values per lookup 65536 by default (max_values)
Scope One dedicated collection per request

Memory used by a walk counts against the request's memory budget like any search. Each engine call is metered like a search.

Errors

Status Code Cause
400 invalid_request A malformed hop, seed group or path spec: an unknown parameter, ids together with query, a non-positive weight, a field that is not a keyword or id field, an adjacency field without an index followed inward, decay or max_per_node on a path edge, min_hop outside 0 to the number of hops, an empty budget, k or weighted with mode: "all", min_depth or max_paths without it, a negative timeout_ms. The message names the parameter, for example edge/hop 0: direction must be out, in or both.
400 invalid_request A lookup resolving more than max_values distinct values, or mixing a string field with a numeric one, or a graph request on a shared collection with namespaced ids.
413 request_too_large The graph request, with all its queries and filters, exceeds your plan's max_query_bytes.
422 limit_exceeded More than 3 hops, max_depth above 6, k above 10, max_paths above 10000, max_nodes, max_edges or a max_frontier above 100000, PPR iterations above 1000, too many seed groups, endpoint ids or engine calls, or a limit above your plan.
429 resource_exhausted A walk reaching more than max_nodes nodes, or traversing more than max_edges edges with subgraph. Lower max_frontier or max_degree, or set budget or timeout_ms. Paths never return 429 for work caps: they report truncated instead.

Not supported yet

Until then, chain graph requests from your application (the ids a request returns are the seeds of the next), and write computed priors back as fields.

View this page as Markdown

Cookie settings

Optional tracking stays off until you choose it. Your choice applies to this browser for 180 days. Read the details.

Essential storage keeps you signed in, protects forms, and remembers this choice. It is always available.