basecamp/trix · error · Error

unserializable object

Error message

unserializable object

What it means

Trix's "application/json" serializer only accepts a trix Document object or an HTMLElement. Any other value (string, plain object, null, undefined) cannot be serialized, so it throws. This is an API-misuse guard in serialization.js's serializers table.

Source

Thrown at action_text-trix/app/assets/javascripts/trix.js:9924

  const stringEndsWithWhitespace = string => /\s$/.test(string);

  /* eslint-disable
      no-empty,
  */
  const unserializableElementSelector = "[data-trix-serialize=false]";
  const unserializableAttributeNames = ["contenteditable", "data-trix-id", "data-trix-store-key", "data-trix-mutable", "data-trix-placeholder", "tabindex"];
  const serializedAttributesAttribute = "data-trix-serialized-attributes";
  const serializedAttributesSelector = "[".concat(serializedAttributesAttribute, "]");
  const blockCommentPattern = new RegExp("<!--block-->", "g");
  const serializers = {
    "application/json": function (serializable) {
      let document;
      if (serializable instanceof Document) {
        document = serializable;
      } else if (serializable instanceof HTMLElement) {
        document = HTMLParser.parse(serializable.innerHTML).getDocument();
      } else {
        throw new Error("unserializable object");
      }
      return document.toSerializableDocument().toJSONString();
    },
    "text/html": function (serializable) {
      let element;
      if (serializable instanceof Document) {
        element = DocumentView.render(serializable);
      } else if (serializable instanceof HTMLElement) {
        element = serializable.cloneNode(true);
      } else {
        throw new Error("unserializable object");
      }

      // Remove unserializable elements
      Array.from(element.querySelectorAll(unserializableElementSelector)).forEach(el => {
        removeNode(el);
      });

View on GitHub (pinned to 4700401311)

Solutions

  1. Pass a trix Document (e.g. from HTMLParser.parse(...).getDocument()) or an HTMLElement to the serializer.
  2. If you have an HTML string, wrap it first: HTMLParser.parse(htmlString).getDocument().
  3. For editor content, use documentView.getDocument() or the editor element's public API instead of hand-built values.
  4. Verify you are not accidentally serializing undefined/null due to an async lookup returning nothing.

Example fix

// before
trix.serializeToContentType(editor.value, "application/json")
// after
const doc = trix.editor.getDocument() // or HTMLParser.parse(html, "text/html").getDocument()
trix.serializeToContentType(doc, "application/json")
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(value instanceof window.Document) && !(value instanceof window.HTMLElement)) {
  throw new TypeError("serializeToContentType expects a Document or HTMLElement")
}

Type guard

function isSerializable(value) {
  return value instanceof Document || value instanceof HTMLElement
}

Try / catch

try {
  return serializeToContentType(value, "application/json")
} catch (e) {
  if (e.message === "unserializable object") {
    return serializeToContentType(HTMLParser.parse(String(value)).getDocument(), "application/json")
  }
  throw e
}

Prevention

When it happens

Trigger: Calling serializeToContentType(value, "application/json") (or the serialized value passed through attachment serialization) with a value that is neither a trix Document nor an HTMLElement, e.g. a raw string of HTML or a JSON object.

Common situations: Passing editor.innerHTML or editor.value (strings) into the serializer instead of an element; calling internal serialization APIs directly; custom attachment serialization hooks that hand off non-DOM values; stale bundled trix.js code where callers relied on older signatures.

Related errors


AI-assisted analysis of basecamp/trix@4700401311 (2026-09-02). Data as JSON: /api/errors/dae033a1d177c9a7. Report an issue: GitHub.