medusajs/medusa · warning
'zone' property at the ${j} index of the 'forms' property is
Error message
'zone' property at the ${j} index of the 'forms' property is not a string literal. The 'zone' property must be a string literal, e.g. 'general' or 'attributes'. What it means
The plugin requires 'zone' to be a string literal because it reads the value at build time via AST parsing; expressions like a variable, template literal, or concatenation cannot be resolved. If zoneProperty.value is not a StringLiteral node, this warning is emitted and the form entry is skipped.
Source
Thrown at packages/admin/admin-vite-plugin/src/custom-fields/generate-custom-field-forms.ts:302
formArray.elements.forEach((element, j) => {
if (!isObjectExpression(element)) {
return
}
const zoneProperty = element.properties.find(
(p) => isObjectProperty(p) && isIdentifier(p.key, { name: "zone" })
) as ObjectProperty | undefined
if (!zoneProperty) {
logger.warn(
`'zone' property is missing from the ${j} index of the 'forms' property. The 'zone' property is required to load a custom field form.`,
{ file }
)
return
}
if (!isStringLiteral(zoneProperty.value)) {
logger.warn(
`'zone' property at the ${j} index of the 'forms' property is not a string literal. The 'zone' property must be a string literal, e.g. 'general' or 'attributes'.`,
{ file }
)
return
}
const tabProperty = element.properties.find(
(p) => isObjectProperty(p) && isIdentifier(p.key, { name: "tab" })
) as ObjectProperty | undefined
let tab: string | undefined
if (tabProperty) {
if (!isStringLiteral(tabProperty.value)) {
logger.warn(
`'tab' property at the ${j} index of the 'forms' property is not a string literal. The 'tab' property must be a string literal, e.g. 'general' or 'attributes'.`,
{ file }
)View on GitHub (pinned to 5e06e544a2)
Solutions
- Inline the literal string: zone: 'general'
- Keep the literal directly in the config file rather than referencing a constant
- If multiple forms share zones, repeat the literal per entry
Example fix
// before
const ZONE = 'general'
forms: [{ zone: ZONE, fields: {...} }]
// after
forms: [{ zone: 'general', fields: {...} }] Defensive patterns
Strategy: type-guard
Validate before calling
for (const [i, f] of forms.entries()) {
if (typeof f.zone !== 'string') throw new Error(`forms[${i}].zone must be an inline string literal`)
} Type guard
const isStringLiteral = (v: unknown): v is string => typeof v === 'string'
Prevention
- Never reference constants for zone/tab values; inline literals only
- Add a unit test asserting every form entry's zone is a plain string
When it happens
Trigger: zone: ZONE constant, zone: `general` (template literal), zone: 'gen'+'eral', or zone: getZone() in a form entry.
Common situations: Extracting zone names into shared constants/imports, using template literals out of habit, or generating configs dynamically.
Related errors
- 'tab' property at the ${j} index of the 'forms' property is
- 'zone' property at the ${j} index of the 'forms' property is
- 'zone' property at index ${j} in the 'displays' property is
- The 'fields' property at the ${j} index of the 'forms' prope
- '${name}' property in the 'fields' property at the ${j} inde
AI-assisted analysis of medusajs/medusa@5e06e544a2 (2026-08-27).
Data as JSON: /api/errors/6970a9d36671bd25.
Report an issue: GitHub.