marmelab/react-admin · error · Error

useSimpleFormIterator must be used inside a SimpleFormIterat

Error message

useSimpleFormIterator must be used inside a SimpleFormIterator

What it means

useSimpleFormIterator exposes the iteration API (add, remove, move, total fields) stored in SimpleFormIteratorContext, which only <SimpleFormIterator> provides. When called outside that context react-admin throws instead of returning undefined methods that would crash later.

Source

Thrown at packages/ra-core/src/controller/input/useSimpleFormIterator.ts:13

import { useContext } from 'react';
import { SimpleFormIteratorContext } from './SimpleFormIteratorContext';

/**
 * A hook that provides access to a SimpleFormIterator data (the total number of items) and mutators (add, reorder and remove).
 * Useful to create custom array input iterators.
 * @see {SimpleFormIterator}
 * @see {ArrayInput}
 */
export const useSimpleFormIterator = () => {
    const context = useContext(SimpleFormIteratorContext);
    if (!context) {
        throw new Error(
            'useSimpleFormIterator must be used inside a SimpleFormIterator'
        );
    }
    return context;
};

View on GitHub (pinned to 051f511bb0)

Solutions

  1. Move the calling component inside <SimpleFormIterator> children so it is below the context provider.
  2. If you control row rendering, use SimpleFormIteratorItem / the row props (fields, remove) passed by the iterator instead of the hook.
  3. For fully custom iterators, provide SimpleFormIteratorContext yourself with add/remove/move functions.

Example fix

// before
<ArrayInput source="items">
  <RemoveItemButton /> {/* throws: outside iterator */}
  <SimpleFormIterator />
</ArrayInput>
// after
<ArrayInput source="items">
  <SimpleFormIterator>
    <RemoveItemButton /> {/* inside iterator context */}
  </SimpleFormIterator>
</ArrayInput>
Defensive patterns

Strategy: type-guard

Type guard

const isInsideSimpleFormIterator = (ctx: SimpleFormIteratorContextValue | null): ctx is SimpleFormIteratorContextValue =>
  ctx != null && typeof ctx.add === 'function' && typeof ctx.remove === 'function';

Try / catch

try {
  const { remove } = useSimpleFormIterator();
} catch (e) {
  if (e.message.includes('useSimpleFormIterator must be used inside')) {
    // fallback: disable the control instead of crashing
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling useSimpleFormIterator in a custom input rendered outside <SimpleFormIterator> — e.g. directly under <ArrayInput>, inside a plain form, or in a button placed as a sibling rather than a child of the iterator.

Common situations: Writing a custom 'delete row' button and placing it outside the <SimpleFormIterator> children; moving the component after a refactor so it is no longer a descendant of the iterator; using the hook inside custom ArrayInput variants that do not use SimpleFormIterator.

Related errors


AI-assisted analysis of marmelab/react-admin@051f511bb0 (2026-08-30). Data as JSON: /api/errors/61d310274a87f917. Report an issue: GitHub.