Budibase/budibase · error · HTTPError

You can't make "${field.name}" readonly because it is a requ

Error message

You can't make "${field.name}" readonly because it is a required field.

What it means

checkRequiredFields also forbids marking required fields as readonly in a view: a basic view field with readonly true on a required table column throws a 400 HTTPError, because users must be able to edit required values.

Source

Thrown at packages/server/src/sdk/workspace/views/index.ts:318

    const viewSchemaField = view.schema?.[field.name]
    const existingViewSchema = existingView?.schema?.[field.name]
    if (!viewSchemaField && !existingViewSchema?.visible) {
      // Supporting existing configs with required columns but hidden in views
      continue
    }

    if (!viewSchemaField?.visible) {
      throw new HTTPError(
        `You can't hide "${field.name}" because it is a required field.`,
        400
      )
    }

    if (
      helpers.views.isBasicViewField(viewSchemaField) &&
      viewSchemaField.readonly
    ) {
      throw new HTTPError(
        `You can't make "${field.name}" readonly because it is a required field.`,
        400
      )
    }
  }
}

export async function create(
  tableId: string,
  viewRequest: Omit<ViewV2, "id" | "version">
): Promise<ViewV2> {
  await guardViewSchema(tableId, viewRequest)
  const view = await pickApi(tableId).create(tableId, viewRequest)

  // Set permissions to be the same as the table
  const tablePerms = await sdk.permissions.getResourcePerms(tableId)
  await sdk.permissions.setPermissions(view.id, {
    writeRole: tablePerms[PermissionLevel.WRITE].role,

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Set readonly: false for that field in the view schema.
  2. Remove the required constraint from the table field if it should be read-only.
  3. Change the field to a non-basic field type if appropriate (non-basic fields bypass this check).

Example fix

// before
view.schema["title"].readonly = true // title is required
// after
view.schema["title"].readonly = false
Defensive patterns

Strategy: validation

Validate before calling

for (const f of Object.keys(table.schema)) {
  if (table.schema[f].constraints?.required && view.schema?.[f]?.readonly) {
    view.schema[f].readonly = false
  }
}

Type guard

function requiredFieldsEditable(view: ViewV2, table: Table): boolean {
  return Object.entries(table.schema).every(([name, f]) =>
    !(f.constraints?.required && view.schema?.[name]?.readonly === true))
}

Try / catch

try {
  await sdk.views.update(view)
} catch (e) {
  if (e instanceof HTTPError && e.status === 400 && e.message.includes("readonly because it is a required field")) {
    // set readonly:false or drop required constraint, then retry
  } else { throw e }
}

Prevention

When it happens

Trigger: create/update via guardViewSchema where helpers.views.isBasicViewField(viewSchemaField) and viewSchemaField.readonly === true for a table field that is required.

Common situations: Locking required columns in the builder UI; scripts that set readonly on all fields uniformly; copying view config from a table where the field wasn't required.

Related errors


AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29). Data as JSON: /api/errors/1ea8804cc6a4c8d2. Report an issue: GitHub.