GrapesJS/grapesjs · error

Cannot remove immutable record

Error message

Cannot remove immutable record

What it means

DataSource.removeRecord refuses to delete records marked immutable (`record.mutable === false`) unless the caller explicitly passes `dangerously` in options. This guards records that bound components depend on from being removed unintentionally.

Source

Thrown at packages/core/src/data_sources/model/DataSource.ts:293

        em.trigger(em.DataSources.events.providerLoadError, { dataSource, error });
      }
    };

    await fetchProvider();
  }

  /**
   * Removes a record from the data source by its ID.
   *
   * @param {string | number} id - The ID of the record to remove.
   * @param {RemoveOptions} [opts] - Options to apply when removing the record.
   * @returns {DataRecord<DRProps> | undefined} The removed data record, or `undefined` if no record is found with the given ID.
   * @name removeRecord
   */
  removeRecord(id: string | number, opts?: RemoveOptions) {
    const record = this.getRecord(id);
    if (record?.mutable === false && !opts?.dangerously) {
      throw new Error('Cannot remove immutable record');
    }

    return this.records.remove(id, opts);
  }

  /**
   * Replaces the existing records in the data source with a new set of records.
   *
   * @param {Array<DRProps>} records - An array of data record properties to set.
   * @returns {Array<DataRecord>} An array of the added data records.
   * @name setRecords
   */
  setRecords(records: DRProps[]) {
    this.records.reset([], { silent: true });

    records.forEach((record) => {
      this.records.add(record);
    });

View on GitHub (pinned to 2bdeda85b8)

Solutions

  1. Call `dataSource.removeRecord(id, { dangerously: true })` if the removal is intentional.
  2. Make the record/schema mutable if records are meant to be managed freely.
  3. Replace the whole record set with `setRecords` excluding the removed record instead of removing it.

Example fix

// before
dataSource.removeRecord(recordId); // throws for immutable record
// after
dataSource.removeRecord(recordId, { dangerously: true });
Defensive patterns

Strategy: validation

Validate before calling

const record = dataSource.getRecord(id);
if (record && record.mutable === false) {
  dataSource.removeRecord(id, { dangerously: true }); // or abort with a UI confirm
} else {
  dataSource.removeRecord(id);
}

Type guard

function isMutable(r) {
  return !!r && r.mutable !== false;
}

Try / catch

try {
  dataSource.removeRecord(id);
} catch (err) {
  if (err.message === 'Cannot remove immutable record') {
    const ok = confirm('This record is immutable. Remove anyway?');
    if (ok) dataSource.removeRecord(id, { dangerously: true });
  } else throw err;
}

Prevention

When it happens

Trigger: Calling `dataSource.removeRecord(id)` on a record with `mutable: false` without `{ dangerously: true }`.

Common situations: Deleting a row fetched from an API whose schema/records are immutable; cleaning up records loaded via a provider; user-driven delete UIs wired to data source records.

Related errors


AI-assisted analysis of GrapesJS/grapesjs@2bdeda85b8 (2026-08-30). Data as JSON: /api/errors/07680790960dff2b. Report an issue: GitHub.