{"record":{"id":"07680790960dff2b","repo":"GrapesJS/grapesjs","slug":"cannot-remove-immutable-record","errorCode":null,"errorMessage":"Cannot remove immutable record","messagePattern":"Cannot remove immutable record","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/core/src/data_sources/model/DataSource.ts","lineNumber":293,"sourceCode":"        em.trigger(em.DataSources.events.providerLoadError, { dataSource, error });\n      }\n    };\n\n    await fetchProvider();\n  }\n\n  /**\n   * Removes a record from the data source by its ID.\n   *\n   * @param {string | number} id - The ID of the record to remove.\n   * @param {RemoveOptions} [opts] - Options to apply when removing the record.\n   * @returns {DataRecord<DRProps> | undefined} The removed data record, or `undefined` if no record is found with the given ID.\n   * @name removeRecord\n   */\n  removeRecord(id: string | number, opts?: RemoveOptions) {\n    const record = this.getRecord(id);\n    if (record?.mutable === false && !opts?.dangerously) {\n      throw new Error('Cannot remove immutable record');\n    }\n\n    return this.records.remove(id, opts);\n  }\n\n  /**\n   * Replaces the existing records in the data source with a new set of records.\n   *\n   * @param {Array<DRProps>} records - An array of data record properties to set.\n   * @returns {Array<DataRecord>} An array of the added data records.\n   * @name setRecords\n   */\n  setRecords(records: DRProps[]) {\n    this.records.reset([], { silent: true });\n\n    records.forEach((record) => {\n      this.records.add(record);\n    });","sourceCodeStart":275,"sourceCodeEnd":311,"githubUrl":"https://github.com/GrapesJS/grapesjs/blob/2bdeda85b82b8b9ceae42fd6558cbbcae5ec2d21/packages/core/src/data_sources/model/DataSource.ts#L275-L311","documentation":"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.","triggerScenarios":"Calling `dataSource.removeRecord(id)` on a record with `mutable: false` without `{ dangerously: true }`.","commonSituations":"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.","solutions":["Call `dataSource.removeRecord(id, { dangerously: true })` if the removal is intentional.","Make the record/schema mutable if records are meant to be managed freely.","Replace the whole record set with `setRecords` excluding the removed record instead of removing it."],"exampleFix":"// before\ndataSource.removeRecord(recordId); // throws for immutable record\n// after\ndataSource.removeRecord(recordId, { dangerously: true });","handlingStrategy":"validation","validationCode":"const record = dataSource.getRecord(id);\nif (record && record.mutable === false) {\n  dataSource.removeRecord(id, { dangerously: true }); // or abort with a UI confirm\n} else {\n  dataSource.removeRecord(id);\n}","typeGuard":"function isMutable(r) {\n  return !!r && r.mutable !== false;\n}","tryCatchPattern":"try {\n  dataSource.removeRecord(id);\n} catch (err) {\n  if (err.message === 'Cannot remove immutable record') {\n    const ok = confirm('This record is immutable. Remove anyway?');\n    if (ok) dataSource.removeRecord(id, { dangerously: true });\n  } else throw err;\n}","preventionTips":["Inspect record.mutable before delete operations","Gate destructive UI actions behind explicit user confirmation when records are immutable","Prefer setRecords with a filtered list over per-record removal for immutable datasets"],"tags":["grapesjs","data-sources","immutability","api-misuse"],"backgroundTag":"immutable-record-modification","analyzedSha":"2bdeda85b82b8b9ceae42fd6558cbbcae5ec2d21","analyzedAt":"2026-08-30T11:47:52.267Z","schemaVersion":2},"datasetVersion":"2026-08-30T13:17:10.514Z"}