Matterhorn 02-003 · PDF/UA-1 UA1:7.1-3
Circular role map: custom tags that never resolve
The role map contains a cycle: A maps to B, B maps back to A. Resolution never terminates.
The condition, as the protocol states it. “A circular mapping exists.”
Matterhorn Protocol 1.1, checkpoint 02, index 02-003, section UA1:7.1-3. Software can decide this one on its own.
How PAC reports it
If you came here from another checker's report, these are its lines for this condition.
- PAC 2024, detailed results: “Structure type "…" is mapped in a circular fashion”
What a screen reader actually does
Processors either abort role resolution or hang; in practice the tags are treated as unknown.
What a loop looks like
A role map translates the producer’s tag names into the vocabulary ISO 32000-1 defines. It may go through more than one step — PDF/UA-1 allows indirect mapping, as long as each chain ends at a standard type — which is what makes a loop possible:
6 0 obj
<< /Type /StructTreeRoot
/K [ 7 0 R ]
/RoleMap << /Sidebar /Box
/Box /Sidebar >>
>>
endobj
To find out what a <Sidebar> element is, a processor looks up Sidebar and gets Box, looks up Box and gets Sidebar, and is back where it started. There is no standard type at the end of the chain because the chain has no end. A name mapped to itself (/Sidebar /Sidebar) is the one-step version.
The loop does not have to contain the names used in the tree. PullQuote → Box, with Box and Panel mapped to each other, leaves every <PullQuote> element in it too.
What breaks
Every element whose type runs into the loop has no meaning a reader can use. A processor that follows the map has to notice it is going round, stop, and fall back on something of its own choosing; one that does not notice never stops.
What is lost is everything the type was for. If the looping names stood for headings, the heading list is short by however many headings used them. If they stood for table cells, the table has no grid. The text is still painted and usually still read; what it is, is gone.
Where it comes from
Loops are almost never written in one go. They come from two edits that are each reasonable: a merge that brings in a second role map with the opposite entry, a hand correction that adds Box → Sidebar without noticing Sidebar → Box was already there, a conversion script that maps unknown names to themselves “for now”. That is also why they survive: the document was fine before the second edit, and nothing on the page changed after it.
How to check it free
Acrobat Pro. In the Tags panel, Options → Edit Role Map. Adobe’s Content and Tags panel documentation describes it as the place to add, change and delete the document’s role mappings. Follow each custom name to its target and keep going until you reach a standard type. If you come back to a name you have already visited, that is the loop.
veraPDF reports role-map faults under clause 7.1.
Acrobat’s Accessibility Checker has no role-mapping rule in the list Adobe publishes.
How to fix it free, in Acrobat Pro
- Tags panel →
Options → Edit Role Map. - Find the names that make up the loop.
- Change one of them to the standard type its content actually is — a sidebar to
Div, a quotation toBlockQuote, a heading to the right level fromH1toH6. - Leave the others pointing at it. They now resolve through it.
- If one of the names in the loop is itself a standard type (
P,Span,H1), delete the entry for that name instead; standard types may not be keys in the role map at all, which is 02-004.
The choice in step 3 is the only judgement in this repair, and it matters: the loop is broken the moment any standard type is there, so a careless pick passes every check and announces the wrong thing everywhere that name is used — 02-002.
Where Taggart differs
The check follows each role-map entry until it reaches a standard type or comes back to a name it has seen, and reports the chain it walked:
The role map contains a circular mapping: Sidebar → Box → Sidebar.
It reports from every name in the loop, and from every name that runs into one — PullQuote → Box → Panel → Box — so the findings list the types affected. A loop is reported as a loop, not also as a chain that fails to terminate (02-001).
The repair, rolemap-repair, is marked safe and runs with Fix All Safe. It goes through the names in alphabetical order and, at the first one that still does not resolve, writes a standard type over its entry; the rest of the loop then resolves through it. The change log says which:
mapped /Box to the standard type /P
The target comes from a table of common producer names — Normal and BodyText to P, Title to H1, Footnote to Note, Hyperlink to Link and so on — and, failing that, from the name itself: H3 or Heading3 becomes that heading level, anything else with head or title in it becomes H1, list becomes L, table becomes Table, figure or image becomes Figure, and everything else becomes P.
Read that change line, because the name it picks is the alphabetically first, not the most meaningful. In a loop between Heading1 and Custom, Custom comes first, the name Custom says nothing, and the entry becomes /P — so every <Heading1> in the document now resolves through Custom to a paragraph. The loop is gone, the role map is valid, and the headings are no longer headings.
The app runs the repair with its own choices and does not let you pick the target. To choose it yourself, break the loop in Acrobat first, as above, and let Taggart check the result.
How Taggart handles it
Taggart checks for this condition automatically and reports it as a blocker, with where in the file it found it.
The fix is Repair the role map. It is mechanical, so “Fix All Safe” applies it along with the others in one pass and lists what it changed. Your original file is never modified.
Whatever Taggart changes, the page still looks identical. Fixes edit the PDF object model, not the content streams, and every remediation is re-rendered and compared against the original at structural similarity ≥ 0.999 before you get the file back. A tool that quietly reflows your document is worse than no tool.
Frequently asked questions
How does a role map end up circular?
Rarely by design. Two documents with opposite mappings are merged into one tree; somebody fixes a mapping by pointing it the other way without deleting the old entry; a script writes an entry that maps a name to itself. Each step looks like an ordinary edit.
Can a loop run through a standard type?
Yes. /P mapped to /Normal and /Normal mapped to /P is a loop, and the /P entry is also condition 02-004, because standard types must not be remapped at all. Remove the /P entry and the loop is gone: Normal then resolves to P.
Which entry should I change?
The one whose meaning you are surest of. Point it at the standard type the content actually is, and every other name in the loop resolves through it. Changing the wrong one gives you a document that passes and announces sidebars as headings.
Does every name in the loop get its own finding?
In Taggart, yes, and so does any name whose chain runs into the loop. A two-name loop is two findings; a third name that maps into it is a third. They share one repair, so the count tells you how many types are affected, not how much work there is.
Where this sits in the standards
| Standard | Reference |
|---|---|
| Matterhorn Protocol 1.1 | Checkpoint 02 (Role Mapping), index 02-003 |
| PDF/UA-1 (ISO 14289-1) | Clause 7.1-3 |
| WCAG 2.1 | 1.3.1 Info and Relationships — Level A |
| EN 301 549 / Section 508 / ADA Title II | All three point at WCAG 2.1 Level AA for non-web documents, so a Level A or AA criterion here is in scope for each of them. |
Related conditions
- 02-001 Non-standard tag mapping does not terminate with a standard typeA custom tag name is present in the role map but the chain of mappings never arrives at a structure type defined in ISO 32000-1, 14.8.4. Mapping may be indirect — a custom type may map to another custom type — but it must eventually terminate.
- 02-004 One or more standard types are remappedA standard structure type appears as a key in the role map — for example /P mapped to /Span. Standard types must never be remapped; doing so redefines the vocabulary the whole file depends on.
- 02-002 Role mapping is semantically inappropriateThe role map terminates at a standard type, but the wrong one — a custom "Sidebar" mapped to Table, or "PullQuote" mapped to Figure.
- 09-003 Structure type is not semantically appropriate after role mappingOnce role mapping has been resolved, the effective type still does not describe the content.
Other conditions in checkpoint 02
Checkpoint 02 covers role mapping. These are its other failure conditions; the ones without a link are in the rule set but do not have a written page yet.
- 02-001 Non-standard tag mapping does not terminate with a standard typeA custom tag name is present in the role map but the chain of mappings never arrives at a structure type defined in ISO 32000-1, 14.8.4. Mapping may be indirect — a custom type may map to another custom type — but it must eventually terminate.
- 02-002 Role mapping is semantically inappropriateThe role map terminates at a standard type, but the wrong one — a custom "Sidebar" mapped to Table, or "PullQuote" mapped to Figure.
- 02-004 One or more standard types are remappedA standard structure type appears as a key in the role map — for example /P mapped to /Span. Standard types must never be remapped; doing so redefines the vocabulary the whole file depends on.
Check your own file. Taggart’s validator is free and unlimited — 75 of the 87 Matterhorn conditions software can decide, with the other 12 listed for you to confirm; no watermark, no expiry, and no account needed up to 60 pages.
Checked with Taggart on a generated file that fails this condition on . The Acrobat steps follow Adobe’s documentation and were not walked through by hand. Last updated .