How to `setNodeMarkup` on a `text` Node

Here is a plugin taken from

new Plugin({
        key: PLUGIN_KEY,
        appendTransaction: (transactions, oldState, newState) => {
          const tr =
          let modified = false
          if (transactions.some(transaction => transaction.docChanged)) {
            newState.doc.descendants((node, pos) => {
              const { uuid: id, } = node.attrs
              if (!id) {
                // Id is not set or already taken => generate and set a new id
                const newId = uuid()
                tr.setNodeMarkup(pos, null, { uuid: newId, })
                modified = true

          if (modified) return tr

But it says

Uncaught Error: NodeType.create can't construct text nodes
    at NodeType.create (
    at Transaction.Transform.setNodeMarkup (
    at index.ts:26

It seems that a text type cannot create in setNodeMarkup:

// :: (number, ?NodeType, ?Object, ?[Mark]) → this
// Change the type, attributes, and/or marks of the node at `pos`.
// When `type` isn't given, the existing node type is preserved,
Transform.prototype.setNodeMarkup = function(pos, type, attrs, marks) {
  let node = this.doc.nodeAt(pos)
  if (!node) throw new RangeError("No node at given position")
  if (!type) type = node.type
  let newNode = type.create(attrs, null, marks || node.marks)
  if (node.isLeaf)
    return this.replaceWith(pos, pos + node.nodeSize, newNode)

  if (!type.validContent(node.content))
    throw new RangeError("Invalid content for node type " +

  return this.step(new ReplaceAroundStep(pos, pos + node.nodeSize, pos + 1, pos + node.nodeSize - 1,
                                         new Slice(Fragment.from(newNode), 0, 0), 1, true))
  // :: (?Object, ?union<Fragment, Node, [Node]>, ?[Mark]) → Node
  // Create a `Node` of this type. The given attributes are
  // checked and defaulted (you can pass `null` to use the type's
  // defaults entirely, if no required attributes exist). `content`
  // may be a `Fragment`, a node, an array of nodes, or
  // `null`. Similarly `marks` may be `null` to default to the empty
  // set of marks.
  create(attrs, content, marks) {
    if (this.isText) throw new Error("NodeType.create can't construct text nodes")
    return new Node(this, this.computeAttrs(attrs), Fragment.from(content), Mark.setFrom(marks))


const isTargetNodeOfType = (node, type) => (node.type === type);


1 Like

This isn’t possible—text nodes are different from other nodes, and don’t have a type or attributes. You’ll have to wrap them in some node if you want to use setNodeMarkup, or use mark add/remove steps if you want to change the set of marks on the text.