> ## Content Index
> Fetch the complete content index at: https://blogs.gardazi.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Fixing a 404 in Medusa's Admin
- URL: https://blogs.gardazi.com/fixing-a-404-in-medusas-admin/
- Published: 2026-08-27T13:22:15.000Z
- Updated: 2026-08-27T13:22:15.000Z
- Description: A shipping profile row linked to a route that was never registered. The fix is one line; the work was proving which of four callers disagreed with the router.
- Author: Syed Talha Ahmed Gardazi
- Tags: Open Source, TypeScript, Debugging

Medusa's admin has a Shipping Profiles list. You click a row, expecting the profile. You get the SPA's "no page at this address" instead.

The profile exists. The API returns it. The row just points at a door that was never built.

## What was wrong

One line, in the table adapter that builds the row links:

```
getRowHref: (row) => `/settings/shipping-profiles/${row.id}`,
```

That path is not a registered route.

## Proving it rather than assuming it

The obvious guess is "the route is missing." It isn't — it's registered somewhere else. The way to be sure is to read the route table rather than the code that links into it.

In `get-route.map.tsx`, the string `path: "shipping-profiles"` appears **exactly once**, and it is nested:

```
settings
└── locations                        (line 1477)
    └── shipping-profiles            (line 1493)
        ├── ""                       → list
        └── :shipping_profile_id     (line 1516) → detail
```

So the only detail route that exists is `/settings/locations/shipping-profiles/:id`. There is no bare `/settings/shipping-profiles` to match, which is why React Router falls through to the catch-all and the SPA renders its 404.

"Appears exactly once" is the part that turns a guess into a fact. If that string had appeared twice, the fix would have been a different conversation.

## The rest of the codebase already knew

Every other place that navigates to a shipping profile uses the full path. The adapter was the only outlier:

| Caller                           | Path                                          |
| -------------------------------- | --------------------------------------------- |
| Product shipping-profile section | /settings/locations/shipping-profiles/${id} ✅ |
| Create form redirect             | /settings/locations/shipping-profiles/${id} ✅ |
| Delete redirect                  | /settings/locations/shipping-profiles ✅       |
| List table adapter               | /settings/shipping-profiles/${id} ❌           |

Three against one. That is about as unambiguous as a bug gets — I didn't have to decide what the correct path *should* be, only which of the four disagreed with the router.

## The fix

```
-    getRowHref: (row) => `/settings/shipping-profiles/${row.id}`,
+    getRowHref: (row) => `/settings/locations/shipping-profiles/${row.id}`,
```

## The part that would have got it rejected

Medusa uses [changesets](https://github.com/changesets/changesets?ref=blogs.gardazi.com). Before opening anything I checked the last eight merged `fix(dashboard)` PRs:

```
#16455 fix(dashboard): reload on preload error        | changeset: YES
#16495 fix(dashboard): fix create fulfillment form    | changeset: YES
#16513 fix(dashboard): remove duplicate Medusa Cloud  | changeset: YES
#16450 fix(dashboard): set the lang attribute         | changeset: YES
... 8 of 8

```

Eight out of eight. A one-line fix with no changeset would have bounced on the first review, and the reviewer's time would have gone on process instead of the bug.

This is the cheapest possible check and I nearly skipped it. Reading merged PRs tells you what a project actually requires, which is not always what CONTRIBUTING.md says — and here it wasn't written down at all.

The PR is [medusajs/medusa#16628](https://github.com/medusajs/medusa/pull/16628?ref=blogs.gardazi.com).

## What I'd take from it

When a link 404s, don't start by asking what the link should say. Find the routing table and count how many times the path segment appears. The router is the only thing that decides what exists; everything else is a claim about it.