overleaf/overleaf · error
Unsupported operation in EditOperationBuilder.fromJSON
Error message
Unsupported operation in EditOperationBuilder.fromJSON
What it means
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.
Source
Thrown at libraries/overleaf-editor-core/lib/operation/edit_operation_builder.js:37
* @returns {EditOperation}
*/
static fromJSON(raw) {
if (isTextOperation(raw)) {
return TextOperation.fromJSON(raw)
}
if (isRawAddCommentOperation(raw)) {
return AddCommentOperation.fromJSON(raw)
}
if (isRawDeleteCommentOperation(raw)) {
return DeleteCommentOperation.fromJSON(raw)
}
if (isRawSetCommentStateOperation(raw)) {
return SetCommentStateOperation.fromJSON(raw)
}
if (isRawEditNoOperation(raw)) {
return EditNoOperation.fromJSON()
}
throw new Error('Unsupported operation in EditOperationBuilder.fromJSON')
}
/**
* @param {unknown} raw
* @return {raw is RawEditOperation}
*/
static isValid(raw) {
return (
isTextOperation(raw) ||
isRawAddCommentOperation(raw) ||
isRawDeleteCommentOperation(raw) ||
isRawSetCommentStateOperation(raw) ||
isRawEditNoOperation(raw)
)
}
}
/**View on GitHub (pinned to 28ad3b03b7)
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.
Example fix
// before
const op = EditOperationBuilder.fromJSON(untrustedJson)
// after
if (!isKnownRawOperation(untrustedJson)) {
throw new ValidationError('unknown edit operation: ' + JSON.stringify(untrustedJson))
}
const op = EditOperationBuilder.fromJSON(untrustedJson) Defensive patterns
Strategy: type-guard
Validate before calling
const KNOWN_RAW_KEYS = ['setCommentState', 'editNo' /* match isRaw* predicates in edit_operation_builder.js */]
function isKnownRawOperation(raw) {
return raw != null && typeof raw === 'object' && KNOWN_RAW_KEYS.some(k => k in raw)
} Type guard
function isRawEditOperation(raw) {
return typeof raw === 'object' && raw !== null &&
(isRawSetCommentStateOperation(raw) || isRawEditNoOperation(raw))
} Try / catch
let op
try {
op = EditOperationBuilder.fromJSON(raw)
} catch (e) {
if (e.message.startsWith('Unsupported operation')) {
log.warn('skipping unknown edit op', raw)
op = null
} else throw e
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- invalid raw operation ${JSON.stringify(raw)}
- Invalid ScanOp ${JSON.stringify(raw)}
- FileData: bad raw object ${JSON.stringify(raw)}
- insert operation must have a string property
- retain operation must have a number property
AI-assisted analysis of overleaf/overleaf@28ad3b03b7 (2026-09-03).
Data as JSON: /api/errors/3f50eb293dd263cb.
Report an issue: GitHub.