{"record":{"id":"58a7c4aaee3695b0","repo":"angular/components","slug":"cannot-begin-editing-a-chip-that-is-not-editable","errorCode":null,"errorMessage":"Cannot begin editing a chip that is not editable.","messagePattern":"Cannot begin editing a chip that is not editable\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/material/chips/testing/chip-row-harness.ts","lineNumber":31,"sourceCode":"\n/** Harness for interacting with a mat-chip-row in tests. */\nexport class MatChipRowHarness extends MatChipHarness {\n  static override hostSelector = '.mat-mdc-chip-row';\n\n  /** Whether the chip is editable. */\n  async isEditable(): Promise<boolean> {\n    return (await this.host()).hasClass('mat-mdc-chip-editable');\n  }\n\n  /** Whether the chip is currently being edited. */\n  async isEditing(): Promise<boolean> {\n    return (await this.host()).hasClass('mat-mdc-chip-editing');\n  }\n\n  /** Sets the chip row into an editing state, if it is editable. */\n  async startEditing(): Promise<void> {\n    if (!(await this.isEditable())) {\n      throw new Error('Cannot begin editing a chip that is not editable.');\n    }\n    return (await this.host()).dispatchEvent('dblclick');\n  }\n\n  /** Stops editing the chip, if it was in the editing state. */\n  async finishEditing(): Promise<void> {\n    if (await this.isEditing()) {\n      await (await this.host()).sendKeys(TestKey.ENTER);\n    }\n  }\n\n  /** Gets the edit input inside the chip row. */\n  async getEditInput(filter: ChipEditInputHarnessFilters = {}): Promise<MatChipEditInputHarness> {\n    return this.locatorFor(MatChipEditInputHarness.with(filter))();\n  }\n}\n","sourceCodeStart":13,"sourceCodeEnd":48,"githubUrl":"https://github.com/angular/components/blob/0411926e7d8ae06b32236ec1048a888cfad5abf2/src/material/chips/testing/chip-row-harness.ts#L13-L48","documentation":"MatChipRowHarness.startEditing() simulates a dblclick to put a chip row into editing mode, but this only works when the chip is configured as editable. The harness checks isEditable() first and throws if the chip is not editable, because the double-click would have no effect.","triggerScenarios":"Calling startEditing() on a chip rendered without the editable input set (e.g. <mat-chip-row> without [editable]=\"true\").","commonSituations":"Testing chip editing flows where the mat-chip-set/grid was created without editable chips; forgetting to bind the editable input after copying test code; testing edit on display-only chips.","solutions":["Set the editable input on the chip: <mat-chip-row editable ...>","Verify with (await harness.isEditable()) before attempting to edit","Ensure the harness targets a chip row (MatChipRowHarness) and not a static non-editable chip"],"exampleFix":"// before\n<mat-chip-row>{{chip.name}}</mat-chip-row>\n// after\n<mat-chip-row editable (edited)=\"rename(chip, $event)\">{{chip.name}}</mat-chip-row>","handlingStrategy":"validation","validationCode":"if (!(await chipHarness.isEditable())) {\n  throw new Error('Chip is not editable; set [editable] on the chip first.');\n}\nawait chipHarness.startEditing();","typeGuard":null,"tryCatchPattern":"try {\n  await chipHarness.startEditing();\n} catch (e) {\n  if ((e as Error).message.includes('not editable')) {\n    // adjust fixture/template to set editable, then retry\n  } else { throw e; }\n}","preventionTips":["Set the editable input on mat-chip-row in the template under test","Check isEditable() before edit operations in harness tests","Use MatChipRowHarness only for chips intended to be edited"],"tags":["angular","material","chips","testing","component-harness","precondition-failed"],"backgroundTag":"operation-not-permitted","analyzedSha":"0411926e7d8ae06b32236ec1048a888cfad5abf2","analyzedAt":"2026-08-31T11:58:23.400Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}