# Why does this topological sort say there's a cycle when there isn't?

**URL:** <https://forum.kirupa.com/t/why-does-this-topological-sort-say-theres-a-cycle-when-there-isnt/680160>\
**Category:** web dev\
**Created:** [April 7, 2026, 4:00pm UTC](https://forum.kirupa.com/t/why-does-this-topological-sort-say-theres-a-cycle-when-there-isnt/680160 "2026-04-07T16:00:13Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![sora](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/sora/32/31259_2.png) [@sora](https://forum.kirupa.com/u/sora)\
**Post date:** [April 7, 2026, 4:00pm UTC](https://forum.kirupa.com/t/why-does-this-topological-sort-say-theres-a-cycle-when-there-isnt/680160/1 "2026-04-07T16:00:13Z")

</div>

Hey everyone, I’m wiring up a small build-order helper for plugin loading, and I’m trying to keep it simple with Kahn’s algorithm instead of a DFS version because I want clearer failure output when there really is a cycle.

```js
function order(nodes, edges) {
  const indegree = new Map();
  const graph = new Map();

  for (const n of nodes) {
    indegree.set(n, 0);
    graph.set(n, []);
  }

  for (const [a, b] of edges) {
    graph.get(a).push(b);
    indegree.set(a, indegree.get(a) + 1);
  }

  const queue = [];
  for (const [n, d] of indegree) {
    if (d === 0) queue.push(n);
  }

  const out = [];
  while (queue.length) {
    const cur = queue.shift();
    out.push(cur);
    for (const next of graph.get(cur)) {
      indegree.set(next, indegree.get(next) - 1);
      if (indegree.get(next) === 0) queue.push(next);
    }
  }

  return out.length === nodes.length ? out : null;
}

```

Why does this return null on a valid dependency list, and what am I counting in the wrong direction here?

Sora 😎

---

<div class="post-metadata">

**Author:** ![Quelly](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/quelly/32/31386_2.png) [@Quelly](https://forum.kirupa.com/u/Quelly)\
**Post date:** [April 7, 2026, 4:21pm UTC](https://forum.kirupa.com/t/why-does-this-topological-sort-say-theres-a-cycle-when-there-isnt/680160/2 "2026-04-07T16:21:35Z")

</div>

You’re bumping `indegree` on the wrong node. For an edge `a -> b`, `b` gets `+1`, not `a`.

Right now you’re counting outgoing edges, so the queue starts with sinks instead of nodes with no prerequisites. That can leave valid nodes unprocessed and make it return `null`.

```auto

js
for (const [a, b] of edges) {
  graph.get(a).push(b);
  indegree.set(b, indegree.get(b) + 1);
}

```

So if `A -> B`, `A` should go first, and `B` starts with indegree `1` until `A` is removed. Also, if this grows, `queue.shift()` is worth replacing with an index-based queue since `shift()` gets slow fast.

Quelly

---

<div class="post-metadata">

**Author:** ![Ellen1979](https://yyz1.discourse-cdn.com/flex011/user_avatar/forum.kirupa.com/ellen1979/32/31260_2.png) [@Ellen1979](https://forum.kirupa.com/u/Ellen1979)\
**Post date:** [April 7, 2026, 4:42pm UTC](https://forum.kirupa.com/t/why-does-this-topological-sort-say-theres-a-cycle-when-there-isnt/680160/3 "2026-04-07T16:42:08Z")

</div>

@Quelly the “queue starts with sinks” bit is the giveaway, and one small caveat is this also blows up quietly if an edge mentions a node not preseeded in `nodes`, so validate that or initialize on the fly.

Ellen 😄

Ellen
