Fonto Why & How: How do I debug validation issues!?

Fonto Why & How: How do I debug validation issues!?

In this weekly series, Martin describes a question that was raised by a Fonto developer, how it was resolved and why Fonto behaved like that in the first place. An error most developers recognize will be ‘the validation for this document failed’. Or operations that just refuse to turn enabled. This post introduces the new validation reporting we launched with Fonto 8.5 and how to use it!

In Fonto 8.5 we improved our validation reporting. Instead of a generic error pointing to the ‘broken’ element, we show more information on which validator detected an error. These errors fall into three main categories:

  • Element validation: which nodes can go where, and what can they contain;

  • Attribute validation: which attributes can go where, and how should they look;

  • Custom validators that do not come from the schema, such as configureAsInvalid.

Load errors

Previous Fonto versions would only show which nodes are broken. For validation issues in operations Fonto would only show a disabled operation, without any other logging.

Element validation

The first one can be see when we put an unknown element, or an existing element at a place where it does not belong. For example, if one puts an <does-not-exist /> element directly in a DITA <body/> element, this will be the error when Fonto loads:

Error: The document clogs/sample.xml failed validation:
	  The content model of this node does not allow does-not-exist as its child.
	  <body id="body_870d8115-e1b8-46c3-f884-38a71ea69715">…</body>

Likewise, when an XML document contains an element on a wrong place, this error is displayed:

Document ID: clogs/clog.xml
	  Error: The document clogs/clog.xml failed validation:
	  The children of this node do not match the restrictions set by its content model.
	  <topic xmlns:xsi="" id="topic_21550622-2577-46a8-ca93-ffa2794f9319" xsi:noNamespaceSchemaLocation="urn:fontoxml:sandbox:names:dita:xsd:topics.xsd">…</topic>

Attribute Validation

Attribute validation can take three forms: a required attribute may not be there, an unknown attribute might exist on an element, or the value of the attribute may not work. All three now give their distinct errors:

Document ID: clogs/clog.xml
	  Error: The document clogs/clog.xml failed validation:
	  This node has an invalid value for attribute id="".
	  <title id=""/>
Document ID: clogs/clog.xml
	  Error: The document clogs/clog.xml failed validation:
	  This node has an unknown attribute: unknown.
	  <title unknown="unknown"/>
Document ID: clogs/tables.xml
	  Error: The document clogs/tables.xml failed validation:
	  This node is missing a required attribute: cols.
	  <tgroup id="tgroup_617d69f8-081b-41ca-bc59-d5282fbb277e">…</tgroup>

Custom Validators

These were usually the hardest to get hold off. configureAsInvalid blocks certain XPaths from matching. If the document loads, and there’s a node for which the selector matches, the document will be seen as invalid. With Fonto 8.5, this selector will now be printed, plus a summary of the offending node.

import xq from 'fontoxml-selectors/src/xq';
	  import configureAsInvalid from 'fontoxml-families/src/configureAsInvalid.js';

	  export default function configureSxModule(sxModule: SxModule) {
	  configureAsInvalid(sxModule, xq`self::title and . => contains("broken")`);
Error: The document clogs/clogs.ditamap failed validation:
	  This node is configured as invalid using selector "self::title and . => contains("broken")".
	  <title id="title_03fcdc0d-a7bd-4239-89a7-4c36c4155003">…</title>

Operation debugging

Besides these better load errors we also introduce an experimental property to Operations to add a similar logging. While this does not yet work for all operations, it does work for all operations that are backed by a custom mutation. Simply set the debugOperation property to true to enable logging for just that operation. Some examples of operations that are backed by a Custom mutation are:


This new feature can be used by adding a flag debugOperation to the data of an operation. You can do this in an operations.json file or directly where you use the operation by passing it into OperationData.

	"debuggable-operation": {
	  "steps": {
	  "type": "operation/execute-update-script",
	  "data": {
	  "expression": "insert node <title>TITLE</title> after $data?contextNode",
      "contextNodeId": "x__fonto:selection-common-ancestor()/ancestor-or-self::*[1]",
	  "debugOperation": true
Custom mutation executeXQueryUpdateFacilityScript: disabled because result is not valid:
	  The content model of this node does not allow title as its child.
	  <body id="body_822246c3-518a-4ce2-dcec-728b75f31b28">…</body>

Why is this still experimental?

This flag is still experimental because not all operations work with it yet. Future releases will enable this flag for all operations. Once we have full coverage and we see this flag is the perfect way to go we will make this public. This operation flag should not end up in production builds. It is similar to console.log, fn:trace or debugger statements. It is meant for debugging, and to be removed when you make a full build.

What is next?

We are doing this because our partners’ biggest frustration is the lack of feedback Fonto gives when a document is broken, or when an operation is disabled. We hope that this will improve your developer experience! Please reach out if you are running into an operation you use a lot that does not have adequate logging yet. We are going to eventually make all operations log their behavior properly. You can help us prioritize by sending a support request with operations you’re using a lot!

I hope this explained how Fonto works and why it works like that. During the years we built quite the product, and we are aware some parts work in unexpected ways for those who have not been with it from the start. If you have any points of Fonto you would like some focus on, we are always ready and willing to share! Reach out on Twitter to Martin Middel or file a support issue!

Stay up-to-dateFonto Why & How posts direct in your inbox

Receive updates on new Fonto Why & How blog posts by email

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top