{"record":{"id":"3f50eb293dd263cb","repo":"overleaf/overleaf","slug":"unsupported-operation-in-editoperationbuilder-from","errorCode":null,"errorMessage":"Unsupported operation in EditOperationBuilder.fromJSON","messagePattern":"Unsupported operation in EditOperationBuilder\\.fromJSON","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"libraries/overleaf-editor-core/lib/operation/edit_operation_builder.js","lineNumber":37,"sourceCode":"   * @returns {EditOperation}\n   */\n  static fromJSON(raw) {\n    if (isTextOperation(raw)) {\n      return TextOperation.fromJSON(raw)\n    }\n    if (isRawAddCommentOperation(raw)) {\n      return AddCommentOperation.fromJSON(raw)\n    }\n    if (isRawDeleteCommentOperation(raw)) {\n      return DeleteCommentOperation.fromJSON(raw)\n    }\n    if (isRawSetCommentStateOperation(raw)) {\n      return SetCommentStateOperation.fromJSON(raw)\n    }\n    if (isRawEditNoOperation(raw)) {\n      return EditNoOperation.fromJSON()\n    }\n    throw new Error('Unsupported operation in EditOperationBuilder.fromJSON')\n  }\n\n  /**\n   * @param {unknown} raw\n   * @return {raw is RawEditOperation}\n   */\n  static isValid(raw) {\n    return (\n      isTextOperation(raw) ||\n      isRawAddCommentOperation(raw) ||\n      isRawDeleteCommentOperation(raw) ||\n      isRawSetCommentStateOperation(raw) ||\n      isRawEditNoOperation(raw)\n    )\n  }\n}\n\n/**","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/overleaf/overleaf/blob/28ad3b03b71cb4311decdcb55c36b33ec10d72db/libraries/overleaf-editor-core/lib/operation/edit_operation_builder.js#L19-L55","documentation":"EditOperationBuilder.fromJSON dispatches a raw JSON object to the correct EditOperation subclass via a chain of type-predicate checks (isRawSetCommentStateOperation, isRawEditNoOperation, etc.). If none of the predicates match, the raw object is not a recognized edit operation, so the builder throws rather than guessing. This guards the deserialization boundary against malformed or unknown payloads.","triggerScenarios":"Calling EditOperationBuilder.fromJSON(raw) where raw is an object not matching any known raw-operation shape: wrong/misspelled discriminator property, null, a string, a number, or an operation type from a newer/older library version.","commonSituations":"Loading persisted history written by a different library version whose schema changed; receiving operations from an untrusted client or an API with validation gaps; hand-written JSON in tests that omits required fields.","solutions":["Inspect the raw object (console.log/JSON.stringify) and compare it against the isRaw*Operation predicates in edit_operation_builder.js to see which discriminator field is missing or wrong.","Validate operation payloads at the ingestion boundary with a schema validator (e.g. zod/ajv) before calling fromJSON.","Check library version compatibility between the producer of the JSON and this parser; upgrade or migrate old persisted ops.","Wrap fromJSON in try/catch and quarantine the unrecognized op instead of crashing the whole deserialization pass."],"exampleFix":"// before\nconst op = EditOperationBuilder.fromJSON(untrustedJson)\n// after\nif (!isKnownRawOperation(untrustedJson)) {\n  throw new ValidationError('unknown edit operation: ' + JSON.stringify(untrustedJson))\n}\nconst op = EditOperationBuilder.fromJSON(untrustedJson)","handlingStrategy":"type-guard","validationCode":"const KNOWN_RAW_KEYS = ['setCommentState', 'editNo' /* match isRaw* predicates in edit_operation_builder.js */]\nfunction isKnownRawOperation(raw) {\n  return raw != null && typeof raw === 'object' && KNOWN_RAW_KEYS.some(k => k in raw)\n}","typeGuard":"function isRawEditOperation(raw) {\n  return typeof raw === 'object' && raw !== null &&\n    (isRawSetCommentStateOperation(raw) || isRawEditNoOperation(raw))\n}","tryCatchPattern":"let op\ntry {\n  op = EditOperationBuilder.fromJSON(raw)\n} catch (e) {\n  if (e.message.startsWith('Unsupported operation')) {\n    log.warn('skipping unknown edit op', raw)\n    op = null\n  } else throw e\n}","preventionTips":["Schema-validate all inbound operation JSON before deserialization.","Pin matching library versions on producer and consumer sides.","Write round-trip tests: serialize -> deserialize every op type you use."],"tags":["deserialization","schema-validation","json","operation"],"backgroundTag":"unknown-operation-type","analyzedSha":"28ad3b03b71cb4311decdcb55c36b33ec10d72db","analyzedAt":"2026-09-03T02:10:22.807Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T07:17:11.731Z"}