spree/spree · error · Error

Slot entry "${name}#${id}" not found.

Error message

Slot entry "${name}#${id}" not found.

What it means

Thrown by updateSlot(name, id, patch) in @spree/dashboard-core when the slot registry has no entry with that id in the named slot — either the slot name is unknown or the id was never registered (registerSlot creates entries; updateSlot only patches). The message identifies the entry as "name#id" so you can see which half of the pair failed.

Source

Thrown at packages/dashboard-core/src/lib/slot-registry.ts:85

export function removeSlot(name: string, id: string): void {
  const list = registry.get(name)
  if (!list) return
  const next = list.filter((e) => e.id !== id)
  if (next.length === list.length) return
  registry.set(name, next)
  notify()
}

export function updateSlot<TContext = unknown>(
  name: string,
  id: string,
  patch: Partial<Omit<SlotEntry<TContext>, 'id'>>,
): void {
  const list = registry.get(name)
  const entry = list?.find((e) => e.id === id)
  if (!list || !entry) {
    throw new Error(`Slot entry "${name}#${id}" not found.`)
  }
  registry.set(
    name,
    list.map((e) => (e.id === id ? ({ ...e, ...patch } as SlotEntry) : e)),
  )
  notify()
}

/**
 * Subscribe to a slot's entries. Re-renders when entries are added/removed/updated
 * so plugins registered after first render still appear.
 *
 * Returned entries are sorted by position (default 100) and stable within ties.
 * Filtering by `if` happens at render time inside <Slot> — the hook returns the
 * full registered list so the caller can decide how to combine context.
 */
export function useSlotEntries(name: string): readonly SlotEntry[] {
  const entries = useSyncExternalStore(

View on GitHub (pinned to 06bf66a868)

Solutions

  1. Verify the slot name and id exactly match the registerSlot call (built-ins are declared in the dashboard shell — check its source for the canonical name)
  2. Track the ids you registered and only update those
  3. Use an upsert helper: catch not-found and fall back to registerSlot with a full entry
  4. Export shared constants for slot names from one module instead of repeating string literals

Example fix

// before
updateSlot('product.form-sidebar', 'acme.wishlist-count', { position: 10 }) // slot name typo

// after
updateSlot('product.form_sidebar', 'acme.wishlist-count', { position: 10 })
// upsert if the entry may not exist yet
try {
  updateSlot('product.form_sidebar', 'acme.wishlist-count', patch)
} catch (err) {
  if (!(err instanceof Error && err.message.includes('not found'))) throw err
  registerSlot('product.form_sidebar', { id: 'acme.wishlist-count', component: WishlistCount, ...patch })
}
Defensive patterns

Strategy: validation

Validate before calling

// Track your own slot ids; never updateSlot a pair you did not register.
import { registerSlot, updateSlot } from '@spree/dashboard-core'

const mySlotIds = new Set<string>()

export function registerMySlot(name: string, entry: SlotEntry): void {
  registerSlot(name, entry)
  mySlotIds.add(`${name}#${entry.id}`)
}

export function updateMySlot(name: string, id: string, patch: Partial<SlotEntry>): void {
  if (!mySlotIds.has(`${name}#${id}`)) return
  updateSlot(name, id, patch)
}

Try / catch

// Upsert: register the full entry when the patch target is missing.
try {
  updateSlot(name, id, patch)
} catch (err) {
  if (!(err instanceof Error && err.message.includes('not found'))) throw err
  registerSlot(name, { id, component: FallbackComponent, ...patch } as SlotEntry)
}

Prevention

When it happens

Trigger: Slot-name typos ('product.form-sidebar' vs 'product.form_sidebar'); id typos or case mismatch; calling updateSlot before the entry was registered; updating an entry a newer dashboard version renamed or removed; updating after removeSlot.

Common situations: Plugins patching built-in slot entries by guessed names/ids; dashboard upgrades reorganizing built-in slots; string constants for slot names drifting between packages.

Related errors


AI-assisted analysis of spree/spree@06bf66a868 (2026-08-21). Data as JSON: /api/errors/83c765cd8958c2b7. Report an issue: GitHub.