initialNodes mutates the graph payload it is given

Open Beginner friendly
#354 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
88/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
typescript
Domain
frontend, testing

Research direction

Start in packages/rad-components/src/components/appgraph/AppGraph.tsx, focusing on initialNodes and the Inbound gateway-direction workaround. Read and run packages/rad-components/src/test/graphInvariants.test.ts to confirm the input graph remains unchanged across repeated use; done means the correction still occurs without mutating the caller's payload.

Written by the indexing model from the issue text.

Description

bug
Steps to reproduce
  1. Render an application graph containing an Applications.Core/gateways resource reached by a connection marked Inbound.
  2. Render the same graph payload object a second time without re-fetching it.
Observed behavior

initialNodes in packages/rad-components/src/components/appgraph/AppGraph.tsx writes to the data it was given:

if (
  connection.direction === 'Inbound' &&
  parsedConnection.type === 'Applications.Core/gateways'
) {
  connection.direction = 'Outbound';
}

The caller's graph object is modified in place. The second render therefore sees different input from the first, because the first render already rewrote it. The function is not idempotent with respect to its argument.

This is currently masked because the graph is re-fetched on each mount, so in practice the object is usually fresh. It stops being masked as soon as the payload is cached, memoized, held in state, passed to two components, or reused in a test — all of which are likely during the graph rearchitecture.

The comment above the block (We have a bug where the connections have the wrong direction) indicates this is a deliberate workaround for upstream data, so the correction itself may be intended. The in-place write is the part that is not.

Desired behavior

initialNodes should treat its argument as read-only and derive the corrected direction locally, rather than mutating the caller's object. A pure function of the graph payload is also a precondition for memoizing the layout, which is worth doing independently.

Workaround

Callers must pass a fresh copy of the graph payload on every render. Tests must deep-clone shared fixtures per use, which is what the new invariant suite does.

Additional context

Pinned by GU-05b in packages/rad-components/src/__test__/graphInvariants.test.ts, added in nicolejms/dashboard#1, tagged KNOWN-DEFECT.

Found while building the graph invariant suite ahead of the graph rearchitecture, tracked in docs/design/2026-09-dashboard-plugin-test-plan.md.

Dominant language
TypeScript
Stars
18
Forks
13
Avg merge
1d 12h
Merged PRs (30d)
10

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from radius-project/dashboard

All issues in radius-project/dashboard

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.