ianstormtaylor/slate · error · Error

Cannot set the "then" property of a node to a function

Error message

Cannot set the "then" property of a node to a function

What it means

Slate refuses to set a node's 'then' property to a function. A thenable node would be treated as a Promise-like object, breaking await behavior, React Suspense, and serialization when nodes are returned from async code.

Source

Thrown at packages/slate/src/interfaces/transforms/general.ts:266

          throw new Error(`Cannot set properties on the root node!`)
        }

        modifyDescendant(editor, path, node => {
          const newNode = { ...node }

          for (const key in newProperties) {
            if (NON_SETTABLE_NODE_PROPERTIES.includes(key)) {
              throw new Error(`Cannot set the "${key}" property of nodes!`)
            }

            const value = newProperties[<keyof Node>key]

            // Make sure we're not setting `then` to a function, since this will
            // cause the node to be treated as a Promise-like object, which can
            // cause unexpected behaviour when returning the node from async
            // functions.
            if (key === 'then' && typeof value === 'function') {
              throw new Error(
                'Cannot set the "then" property of a node to a function'
              )
            }

            if (value == null) {
              delete newNode[<keyof Node>key]
            } else {
              newNode[<keyof Node>key] = value
            }
          }

          // properties that were previously defined, but are now missing, must be deleted
          for (const key in properties) {
            if (!Object.hasOwn(newProperties, key)) {
              delete newNode[<keyof Node>key]
            }
          }

View on GitHub (pinned to 72a37c701e)

Solutions

  1. Whitelist the keys you set: only copy known-safe property keys instead of spreading whole objects into setNodes.
  2. Strip 'then' (and any function-valued keys) from deserialized properties before applying.
  3. If you genuinely need a then field, store it as a non-function value or under a different key.

Example fix

// before
Transforms.setNodes(editor, props, { at: path }) // props may contain then

// after
const safe = Object.fromEntries(
  Object.entries(props).filter(
    ([k, v]) => k !== 'then' && typeof v !== 'function'
  )
)
Transforms.setNodes(editor, safe, { at: path })
Defensive patterns

Strategy: validation

Validate before calling

const safe = Object.fromEntries(
  Object.entries(props).filter(
    ([k, v]) => k !== 'then' && typeof v !== 'function'
  )
)
Transforms.setNodes(editor, safe, { at: path })

Type guard

function hasNoThenFunction(props: Record<string, unknown>): boolean {
  return !('then' in props) || typeof props.then !== 'function'
}

Prevention

When it happens

Trigger: Applying set_node where newProperties.then is a function — typically accidental, e.g. spreading an object containing a then callback into Transforms.setNodes props, or deserializing untrusted JSON into node properties.

Common situations: Spreading arbitrary/foreign objects into node properties; accepting node JSON from untrusted input; test fixtures accidentally including a then function.

Related errors


AI-assisted analysis of ianstormtaylor/slate@72a37c701e (2026-08-27). Data as JSON: /api/errors/b461f1d18b6931d4. Report an issue: GitHub.