medusajs/medusa · warning

The 'fields' property at the ${j} index of the 'forms' prope

Error message

The 'fields' property at the ${j} index of the 'forms' property is malformed. The 'fields' property must be an object.

What it means

The 'fields' property of a form entry must be a plain object expression mapping field names to definitions. If the AST value is an array, identifier, call, or anything other than an ObjectExpression, this warning is emitted and the entry is skipped.

Source

Thrown at packages/admin/admin-vite-plugin/src/custom-fields/generate-custom-field-forms.ts:364

      return
    }

    const fieldsObject = element.properties.find(
      (p) => isObjectProperty(p) && isIdentifier(p.key, { name: "fields" })
    ) as ObjectProperty | undefined

    if (!fieldsObject) {
      logger.warn(
        `The 'fields' property is missing at the ${j} index of the 'forms' property. The 'fields' property is required to load a custom field form.`,
        { file }
      )
      return
    }

    const fields: CustomFieldFormField[] = []

    if (!isObjectExpression(fieldsObject.value)) {
      logger.warn(
        `The 'fields' property at the ${j} index of the 'forms' property is malformed. The 'fields' property must be an object.`,
        { file }
      )
      return
    }

    fieldsObject.value.properties.forEach((field) => {
      if (!isObjectProperty(field) || !isIdentifier(field.key)) {
        return
      }

      const name = field.key.name

      if (
        !isObjectExpression(field.value) &&
        !(
          isCallExpression(field.value) &&
          isMemberExpression(field.value.callee) &&

View on GitHub (pinned to 5e06e544a2)

Solutions

  1. Change 'fields' to an inline object literal keyed by field name
  2. Inline imported/constant field definitions directly into the config
  3. Use form.define({...}) per field key if defining component-backed fields

Example fix

// before
forms: [{ zone: 'general', fields: [myFieldDef] }]
// after
forms: [{ zone: 'general', fields: { myField: form.define({ ... }) } }]
Defensive patterns

Strategy: type-guard

Validate before calling

if (Array.isArray(f.fields) || typeof f.fields !== 'object') {
  throw new Error('fields must be a plain object, not an array')
}

Type guard

const isPlainObject = (v: unknown): v is Record<string, unknown> =>
  typeof v === 'object' && v !== null && !Array.isArray(v)

Prevention

When it happens

Trigger: fields: [field1, field2], fields: myFields (imported variable), or fields: getFields().

Common situations: Assuming fields is a list like the outer 'forms' array, or trying to DRY configs by extracting the fields object to a variable (unsupported because parsing is static).

Understand the failure class

Related errors


AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27). Data as JSON: /api/errors/3c001d70a9b76ec4. Report an issue: GitHub.