overleaf/overleaf · error · InvalidInsertionError
insertion must be a string
Error message
insertion must be a string
What it means
InsertOp represents an insertion of text into a document, so its `insertion` payload must be a string. The constructor explicitly type-checks and throws InvalidInsertionError when given a non-string (number, undefined, object, etc.). This fails fast so a malformed insert never propagates into document transforms.
Source
Thrown at libraries/overleaf-editor-core/lib/operation/scan_op.js:97
throw new Error('abstract method')
}
toString() {
'ScanOp'
}
}
class InsertOp extends ScanOp {
/**
*
* @param {string} insertion
* @param {TrackingProps | undefined} tracking
* @param {string[] | undefined} commentIds
*/
constructor(insertion, tracking = undefined, commentIds = undefined) {
super()
if (typeof insertion !== 'string') {
throw new InvalidInsertionError('insertion must be a string')
}
if (containsNonBmpChars(insertion)) {
throw new InvalidInsertionError('insertion contains non-BMP characters')
}
/** @type {string} */
this.insertion = insertion
/** @type {TrackingProps | undefined} */
this.tracking = tracking
/** @type {string[] | undefined} */
this.commentIds = commentIds
}
/**
*
* @param {RawInsertOp} op
* @returns {InsertOp}
*/
static fromJSON(op) {View on GitHub (pinned to 28ad3b03b7)
Solutions
- Coerce or validate the insertion to a string before constructing: String(value) or a typeof check.
- If the value comes from JSON, use InsertOp.fromJSON(op) which validates the `i` property and gives a clearer error path.
- Fix the upstream code path producing undefined/null insertion values (often a missing field in fetched data).
Example fix
// before
new InsertOp(payload.insertion) // payload.insertion may be undefined
// after
if (typeof payload.insertion !== 'string') throw new TypeError('insertion required')
new InsertOp(payload.insertion) Defensive patterns
Strategy: validation
Validate before calling
if (typeof insertion !== 'string') {
throw new TypeError('insertion must be a string before building InsertOp')
} Type guard
function isStringInsertion(v) { return typeof v === 'string' } Try / catch
try {
op = new InsertOp(insertion)
} catch (e) {
if (e instanceof InvalidInsertionError && e.message.includes('must be a string')) {
op = new InsertOp(String(insertion ?? ''))
} else throw e
} Prevention
- Coerce API/form values with String(value) before building ops.
- Use InsertOp.fromJSON for untrusted data — it validates the raw shape.
- Typecheck code paths with JSDoc/TS so non-strings are caught statically.
When it happens
Trigger: Calling `new InsertOp(value)` where value is not a string: `new InsertOp(42)`, `new InsertOp(undefined)` after a failed lookup, or passing raw JSON like `{ i: 5 }` fields directly instead of going through fromJSON.
Common situations: Deserializing JSON where the insertion field is a number/null; constructing ops programmatically from computed values that turned out undefined; form/API input not coerced to string before building ops.
Related errors
- insertion contains non-BMP characters
- insert operation must have a string property
- length must be non-negative
- retain operation must have a number property
- Inserts must insert a string or a +ive number
AI-assisted analysis of overleaf/overleaf@28ad3b03b7 (2026-09-03).
Data as JSON: /api/errors/bb70c079774f97d5.
Report an issue: GitHub.