strapi/strapi · error · Error

The attribute "${attributeName}" is reserved and cannot be u

Error message

The attribute "${attributeName}" is reserved and cannot be used in a model. Please rename "${contentType.modelName}" attribute "${attributeName}" to something else.

What it means

Thrown during content-type-to-model transformation when a user-defined attribute snake-cases to 'document_id' or to the DB id column (identifiers.ID_COLUMN, conventionally 'id'). These names are reserved because Strapi auto-injects a documentId attribute and an auto-increment id column into every content type; allowing a user attribute with the same DB column name would cause a schema collision.

Source

Thrown at packages/core/core/src/utils/transform-content-types-to-models.ts:297

  contentTypes.forEach((contentType) => {
    assert(contentType.collectionName, 'Content type "collectionName" is required');
    assert(contentType.modelName, 'Content type "modelName" is required');
    assert(contentType.uid, 'Content type "uid" is required');

    // Add document id to content types
    // as it is not documented
    const documentIdAttribute: Record<string, Schema.Attribute.AnyAttribute> =
      contentType.modelType === 'contentType'
        ? { documentId: { type: 'string', default: createDocumentId } }
        : {};

    // TODO: this needs to be combined with getReservedNames, we should not be maintaining two lists
    // Prevent user from creating a documentId attribute
    const reservedAttributeNames = ['document_id', identifiers.ID_COLUMN];
    Object.keys(contentType.attributes || {}).forEach((attributeName) => {
      const snakeCasedAttributeName = _.snakeCase(attributeName);
      if (reservedAttributeNames.includes(snakeCasedAttributeName)) {
        throw new Error(
          `The attribute "${attributeName}" is reserved and cannot be used in a model. Please rename "${contentType.modelName}" attribute "${attributeName}" to something else.`
        );
      }
    });

    if (hasComponentsOrDz(contentType)) {
      const compoLinkModel = createCompoLinkModel(contentType, identifiers);
      models.push(compoLinkModel);
    }

    const model: Model = {
      uid: contentType.uid,
      singularName: contentType.modelName,
      tableName: contentType.collectionName, // This gets shortened in metadata.loadModels(), so we don't shorten here or it will happen twice
      attributes: {
        [identifiers.ID_COLUMN]: {
          type: 'increments',
        },

View on GitHub (pinned to 4a4101264d)

Solutions

  1. Rename the offending attribute to something that does not snake-case to 'id' or 'document_id' (e.g. 'documentRef', 'externalId', 'customId').
  2. Search the content type's schema.json for keys named id, documentId, document_id and remove or rename them.
  3. After renaming, clear the rebuilt model cache and restart Strapi.

Example fix

// before — src/api/article/content-types/article/schema.json
{ "attributes": { "documentId": { "type": "string" } } }
// after
{ "attributes": { "externalDocumentId": { "type": "string" } } }
Defensive patterns

Strategy: validation

Validate before calling

const RESERVED = ['id', 'document_id'];
const snake = (s) => s.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toLowerCase();
const offenders = Object.keys(schema.attributes).filter((name) => RESERVED.includes(snake(name)));
if (offenders.length) {
  throw new Error(`Reserved attribute names: ${offenders.join(', ')}`);
}

Type guard

const isReservedAttributeName = (name: string): boolean => {
  const snake = name.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toLowerCase();
  return ['id', 'document_id'].includes(snake);
};

Prevention

When it happens

Trigger: Defining a content type whose schema.json attributes include 'documentId', 'document_id', 'id', 'ID', or any casing that snake-cases to 'document_id' or 'id'. Fires at Strapi boot during metadata loading, before the server starts.

Common situations: Migrating from Strapi v4 (where 'id' was the only identifier) to v5 (which adds documentId) and keeping a custom 'id'-like attribute; naming a field 'documentId' for a business concept; importing a content type schema from another system that uses those names.

Related errors


AI-assisted analysis of strapi/strapi@4a4101264d (2026-08-12). Data as JSON: /api/errors/da2e88d0277789b4. Report an issue: GitHub.