mastra-ai/mastra · error · Error

useJSONSchemaForm must be used within a JSONSchemaForm.Root

Error message

useJSONSchemaForm must be used within a JSONSchemaForm.Root

What it means

useJSONSchemaForm returns the shared form state (addField, fields, updateField, maxDepth, etc.) from JSONSchemaFormContext, which only JSONSchemaForm.Root provides. Outside a Root the context is null and the hook throws, guaranteeing form subcomponents always have valid form state.

Source

Thrown at packages/playground-ui/src/ds/components/JSONSchemaForm/json-schema-form-context.tsx:27

  maxDepth: number;
}

const JSONSchemaFormContext = React.createContext<JSONSchemaFormContextValue | null>(null);

export function JSONSchemaFormProvider({
  children,
  value,
}: {
  children: React.ReactNode;
  value: JSONSchemaFormContextValue;
}) {
  return <JSONSchemaFormContext.Provider value={value}>{children}</JSONSchemaFormContext.Provider>;
}

export function useJSONSchemaForm(): JSONSchemaFormContextValue {
  const context = React.useContext(JSONSchemaFormContext);
  if (!context) {
    throw new Error('useJSONSchemaForm must be used within a JSONSchemaForm.Root');
  }
  return context;
}

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Move the consumer inside <JSONSchemaForm.Root schema={...}>...</JSONSchemaForm.Root>.
  2. If the UI must live outside the Root element, lift the Root higher so the whole form subtree is covered, or pass the needed callbacks as explicit props instead of using the hook.
  3. For modals/portals, render them within Root's subtree (React context crosses portals, but not tree boundaries — keep Root as an ancestor).
  4. Add a useMaybeJSONSchemaForm-style nullable accessor if optional usage is a real requirement.

Example fix

// before
<AddFieldButton /> // outside Root
// after
<JSONSchemaForm.Root schema={schema} onSubmit={submit}>
  <AddFieldButton />
</JSONSchemaForm.Root>
Defensive patterns

Strategy: try-catch

Validate before calling

// Ensure JSONSchemaForm.Root wraps all consumers of useJSONSchemaForm.
// Optional access pattern:
const ctx = React.useContext(JSONSchemaFormContext);
if (!ctx) console.warn('useJSONSchemaForm consumer must be nested in JSONSchemaForm.Root');

Type guard

function hasFormContext(c: JSONSchemaFormContextValue | null): c is JSONSchemaFormContextValue {
  return c !== null;
}

Try / catch

// Hooks cannot be try/catch-wrapped; use an error boundary at the form section level:
<ErrorBoundary fallback={<InvalidFormUsage /> }>
  <MyAddFieldButton />
</ErrorBoundary>

Prevention

When it happens

Trigger: Calling useJSONSchemaForm in a component rendered outside <JSONSchemaForm.Root> — e.g. a custom add-field button or field list placed outside the Root, or a child lifted into a separate tree (portal/modal without its own Root).

Common situations: Building custom form chrome (toolbar, add field button) and forgetting to place it inside Root; rendering the form's field list in a parent component for layout reasons; storybook examples mounting subcomponents in isolation.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/445b293653a324f2. Report an issue: GitHub.