marmelab/react-admin · error

SimpleFormIterator can only be called within an iterator inp

Error message

SimpleFormIterator can only be called within an iterator input like ArrayInput

What it means

SimpleFormIteratorBase manages the rows of an array field; it discovers the field source via useWrappedSource(''), which is only populated inside an iterator context (ArrayInput). If the resolved source is empty it means the component is not inside an ArrayInput, so row operations (append/remove/move) have no target and react-admin throws.

Source

Thrown at packages/ra-core/src/controller/input/SimpleFormIteratorBase.tsx:22

import { useWrappedSource } from '../../core/useWrappedSource';
import type { RaRecord } from '../../types';
import { useEvent } from '../../util';
import { useArrayInput } from './useArrayInput';
import { SimpleFormIteratorContext } from './SimpleFormIteratorContext';

const DefaultGetItemDefaults = item => item;

export const SimpleFormIteratorBase = (props: SimpleFormIteratorBaseProps) => {
    const {
        children,
        getItemDefaults: getItemDefaultsProp = DefaultGetItemDefaults,
        disableAutoFocus = false,
    } = props;
    const getItemDefaults = useEvent(getItemDefaultsProp);

    const finalSource = useWrappedSource('');
    if (!finalSource) {
        throw new Error(
            'SimpleFormIterator can only be called within an iterator input like ArrayInput'
        );
    }

    const { append, fields, move, remove } = useArrayInput(props);
    const { trigger, getValues } = useFormContext();

    const removeField = useEvent((index: number) => {
        remove(index);
        const isScalarArray = getValues(finalSource).every(
            (value: any) => typeof value !== 'object'
        );
        if (isScalarArray) {
            // Trigger validation on the Array to avoid ghost errors.
            // Otherwise, validation errors on removed fields might still be displayed
            trigger(finalSource);
        }
    });

View on GitHub (pinned to 051f511bb0)

Solutions

  1. Wrap it in <ArrayInput source="items"><SimpleFormIterator>...</SimpleFormIterator></ArrayInput>
  2. For a generic repeater outside react-admin forms, use react-hook-form's useFieldArray directly
  3. In tests, render inside a full <Form><ArrayInput> structure

Example fix

// before
<TextInput source="title" />
<SimpleFormIterator>
  <TextInput source="name" />
</SimpleFormIterator>
// after
<ArrayInput source="items">
  <SimpleFormIterator>
    <TextInput source="name" />
  </SimpleFormIterator>
</ArrayInput>
Defensive patterns

Strategy: validation

Validate before calling

const src = useWrappedSource('');
if (!src) throw new Error('Must be inside ArrayInput');

Type guard

const inArrayInput = (s: string | undefined): s is string =>
  !!s && s.length > 0;

Try / catch

try {
  render(<Form><SimpleFormIterator><TextInput source="name"/></SimpleFormIterator></Form>);
} catch (e) { logAndFallback(e); }

Prevention

When it happens

Trigger: Rendering <SimpleFormIterator> outside <ArrayInput> (e.g. inside a regular TextInput, in a custom form section, or directly in a Show view); using it as a generic repeater without the array input wrapper.

Common situations: Reusing the iterator UI for ad-hoc repeatable fields; nesting mistakes where the iterator is placed under a different input component; tests rendering SimpleFormIterator standalone.

Related errors


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