Neo4j GDS Certification common mistakes
Neo4j GDS Certification · Understand the traps and how to avoid them.
Calling gds.graph.project with a node label and relationship type that don't exist, then assuming the algorithm is broken when it returns a graph with zero nodes or throws a projection error.
Candidates memorize the projection syntax but never verify the actual label/relationship strings in the database, and Cypher label matching is case- and spelling-sensitive. The projection silently succeeds on an empty match or fails with a generic error, so the candidate misdiagnoses the problem as an algorithm issue.
What to do instead
Before projecting, run MATCH (n:Label) RETURN count(n) and MATCH ()-[r:TYPE]->() RETURN count(r) to confirm the exact strings and non-zero counts. Then project and immediately call gds.graph.nodeCount / relationshipCount (or gds.graph.list) to verify the projected graph has the expected node and relationship counts before running any algorithm.
Treating gds.graph.project as a one-time setup and re-projecting the same graph name repeatedly, hitting a 'graph already exists' error, or conversely leaving stale projections in memory that consume heap until the database runs out of memory.
The in-memory graph catalog is persistent across queries within a session/database, but candidates coming from a pure-Cypher background assume each query starts fresh. They also underestimate that each projection holds a full copy of the topology and properties in heap.
What to do instead
Use gds.graph.exists('name') to check before projecting, or project with a unique name per run. Explicitly call gds.graph.drop('name') when done, and monitor with gds.graph.list() to see memoryUsage per graph. In exam scenarios, drop old graphs before creating new ones with the same name.
Confusing the write mode, mutate mode, and stream mode of an algorithm and using the wrong one for the requested output (e.g., streaming results when the task asks for properties persisted to the graph, or writing when only an estimate is needed).
All three modes share the same algorithm signature and differ only by the mode suffix, so candidates default to whatever they used last. The exam deliberately phrases tasks around where the result must end up, and candidates skim past 'persist' versus 'return'.
What to do instead
Learn the three execution modes as a fixed decision rule: stream returns rows to the client and stores nothing; mutate writes results into the in-memory graph only (for chaining algorithms); write persists results as node/relationship properties in the database. Read the task's required output before choosing the mode, and remember stats mode is a separate lightweight call for cost estimation.
Running an algorithm in mutate or write mode without setting the required parameters, or passing parameters as strings/incorrect types, causing errors or silently wrong results (e.g., missing relationshipWeightProperty, wrong dampingFactor type, or omitting concurrency).
Candidates memorize the algorithm name but not the full parameter contract, and Cypher's type coercion means some wrong types are accepted while others error. Weighted algorithms in particular produce unweighted results if the weight property isn't named correctly.
What to do instead
Memorize the parameter block for each algorithm family: PageRank (dampingFactor, maxIterations, tolerance, relationshipWeightProperty), Louvain (maxLevels, tolerance, relationshipWeightProperty), Dijkstra (relationshipWeightProperty, sourceNode), WCC (threshold, relationshipWeightProperty). Verify the weight property exists on relationships with MATCH ()-[r:TYPE]->() RETURN r.weight LIMIT 5 before running.
Using the wrong algorithm for the graph shape or question: running Louvain on a graph with no meaningful community structure, using Dijkstra on unweighted graphs and expecting different results from BFS, or applying PageRank to a directed graph without considering direction.
Candidates learn algorithms by name and formula but not by the input assumptions each one makes. The exam tests whether you can match a business question (shortest path, influence, clustering, connectivity) to the algorithm whose assumptions fit the data.
What to do instead
Build a mapping table: shortest weighted path -> Dijkstra or A*; unweighted shortest path -> BFS; influence/importance -> PageRank or ArticleRank; community detection -> Louvain or Label Propagation; connectivity -> WCC or SCC; similarity -> Node Similarity or KNN. Before answering, check whether the graph is weighted and directed, and pick the algorithm whose assumptions match.
Constructing a Cypher projection with a query that returns the wrong column names, or returning extra columns, so gds.graph.project.cypher fails or projects an unexpected schema.
Cypher projections require the node query to return exactly id and optionally labels, and the relationship query to return source, target, and optionally type and properties. Candidates write natural Cypher with aliases like n.id or AS nodeId, which don't match the required contract.
What to do instead
Use the exact contract: node query must RETURN id, and optionally labels; relationship query must RETURN source, target, and optionally type plus property columns. Test the queries standalone in the browser first, confirm column names, then pass them to gds.graph.project.cypher. Prefer native projections when the schema allows, since they are faster and less error-prone.
Ignoring the estimated memory requirement from gds.graph.project or the algorithm's stats mode, then hitting out-of-memory errors or extremely slow runs during the exam.
Candidates focus on correctness and skip the estimation step, not realizing that projections and algorithms each allocate significant heap and that the exam may test awareness of memory management and concurrency settings.
What to do instead
Run the algorithm in stats mode first to get requiredMemory and treeView, and compare against available heap. Reduce graph size with node/relationship filters or subgraph projections, lower concurrency, or use a smaller relationshipWeightProperty set. Know that gds.graph.project returns nodeCount, relationshipCount, and memoryUsage you can inspect.
Misreading the output of a similarity or community algorithm: treating similarity scores as symmetric when using directed relationships, or interpreting Louvain modularity as a quality guarantee rather than a relative measure.
Candidates read the numeric output literally without understanding what the metric means. Node Similarity with directed relationships computes directional similarity, and modularity values are only comparable within a run and depend on resolution and graph structure.
What to do instead
Check relationship direction before interpreting similarity: undirected relationships yield symmetric scores, directed ones do not. For Louvain, compare modularity across runs and levels rather than treating a single value as good or bad, and inspect community sizes with a follow-up query grouping by community property. Always validate clustering output against domain expectations.
Assuming GDS algorithms are available as plain Cypher functions or that the gds library is loaded by default, then writing queries that fail with 'unknown function gds...' or 'no procedure with name gds...'.
Candidates conflate the GDS plugin with core Cypher and don't verify installation, plugin version compatibility with the Neo4j server version, or that the procedure namespace is gds.* rather than db.* or algo.* (the older library name).
What to do instead
Verify the plugin is installed and enabled with SHOW PROCEDURES YIELD name WHERE name STARTS WITH 'gds' RETURN name (or CALL gds.list()). Confirm the GDS version matches the Neo4j server version. Remember the namespace is gds.* and that older algo.* procedures belong to the deprecated Graph Algorithms library, not GDS.
Skipping the workflow ordering: writing algorithm results before projecting, or chaining mutate and stream in the wrong order, so downstream steps read stale or missing properties.
Candidates treat each GDS call as independent and don't internalize the project -> estimate -> execute -> consume -> drop lifecycle. The exam tests whether you know that mutate must precede any algorithm that consumes the mutated property, and that write persists only at the end.
What to do instead
Follow the canonical workflow every time: (1) gds.graph.project, (2) optional stats-mode estimate, (3) run algorithm in mutate mode to store intermediate results, (4) run downstream algorithm or stream/write to consume results, (5) gds.graph.drop. When chaining (e.g., Louvain then PageRank within communities), mutate the community property first, then use it as a nodeProperty or filter.