# Bug report — Spire.Doc 14.8.4 / Spire.XLS 16.8.4
## PDF/A output declares a conformance level it does not meet
**Products:** Spire.Doc for Java 14.8.4, Spire.XLS for Java 16.8.4
(both from BOM `e-iceblue:spire.office:11.8.0`)
**Severity:** correctness — the output is *silently* non-conforming. The file
identifies itself as PDF/A-2a/3a in its XMP metadata, so nothing in the application
signals a problem; it only surfaces when someone validates the archive.
**Platform:** reproducible on Windows and Linux alike.
### Summary
`ToPdfParameterList.setPdfConformanceLevel(PdfConformanceLevel.Pdf_A_2_A)` (and
`Pdf_A_3_A`) writes the correct conformance claim into the document metadata, but
the produced content violates the corresponding ISO 19005 requirements — on
**every one of 11 test documents**, with 102–119 violations each.
The same applies to `Spire.XLS` at PDF/A-1a, for a different reason (see below).
Validated with **veraPDF 1.26.2**, the reference implementation of ISO 19005.
The flavour is auto-detected from the file's own metadata, so the validator is
checking each file against exactly the level that file claims.
### Results
| engine | format | PDF/A-1b | PDF/A-1a | PDF/A-2a | PDF/A-3a |
|---|---|---|---|---|---|
| **Spire.Doc 14.8.4** | RTF, DOC, DOCX | 11/11 ✔ | 11/11 ✔ | **0/11 ✘** | **0/11 ✘** |
| **Spire.XLS 16.8.4** | XLSX | 1/1 ✔ | **0/1 ✘** | **0/1 ✘** | **0/1 ✘** |
| Aspose.Words 25.11 *(for reference)* | RTF, DOC, DOCX | 11/11 ✔ | 11/11 ✔ | 11/11 ✔ | 11/11 ✔ |
| Aspose.Cells via GroupDocs 26.7 *(for reference)* | XLSX | 1/1 ✔ | 1/1 ✔ | 1/1 ✔ | 1/1 ✔ |
A competing library produces valid output at all four levels on the same corpus,
so the levels themselves are achievable for these documents.
Violations per document, Spire.Doc at PDF/A-2a (identical set at 3a):
```
SPOD.rtf 119
os_oznameni_prestupku-362-20260902 108
os_donucovak.doc / .docx / .rtf 104
os_donucovak_small.rtf 104
Příkaz.rtf 104
aa_draha_173_1995_8_1.rtf 102
PP.rtf 102
RL_žádost.rtf 102
Lístek.rtf 14
```
(veraPDF caps reporting at 100 occurrences per rule, so the real counts are higher.)
---
## Issue 1 — Spire.Doc, PDF/A-2 and PDF/A-3: font-level violations
Three rules are broken; the first one dominates by volume.
### 6.2.11.7.2 test 2 — object `Glyph`
> The Unicode values specified in the ToUnicode CMap shall all be greater than
> zero (0), but not equal to either U+FEFF or U+FFFE
```
test: toUnicode == null || (toUnicode.indexOf("\ 00") == -1
&& toUnicode.indexOf("\ EFBFBE") == -1
&& toUnicode.indexOf("\ EFBBBF") == -1)
location: root/document[0]/pages[0](6 0 obj PDPage)/contentStream[0]
/operators[107]/usedGlyphs[0](FAAABJ+Arial-BoldMT ...)
```
Spire writes **U+0000 entries into the `ToUnicode` CMap**. Occurs 100+ times per
document (report cap), across ordinary embedded subsets such as `Arial-BoldMT`.
### 6.2.11.4.2 test 2 — object `PDCIDFont`
> If the FontDescriptor dictionary of an embedded CID font contains a CIDSet
> stream, then it shall identify all CIDs which are present in the font program,
> regardless of whether a CID in the font is referenced or used by the PDF or not
```
location: .../font[0](FAAABJ+Arial-BoldMT)/DescendantFonts[0](FAAABJ+Arial-BoldMT)
```
The emitted `CIDSet` does not list every CID present in the embedded subset.
### 6.2.11.7.3 test 1 — object `Glyph`
> For any character ... mapped to a code or codes in the Unicode Private Use Area
> (PUA), an ActualText entry ... shall be present
```
location: .../usedGlyphs[0](FAAAFF+SymbolMT ...)
```
Symbol-font glyphs land in the PUA and are emitted without `ActualText`.
### Why PDF/A-1 passes and PDF/A-2 does not
None of these three rules exist in ISO 19005-1. They were introduced in
ISO 19005-2. So this is not document-specific luck — **Spire.Doc does not
implement the font requirements added in PDF/A-2, yet still advertises
conformance to it.**
---
## Issue 2 — Spire.XLS, PDF/A-1a: level claimed, tags not produced
Two rules, both structural:
### 6.8.2.2 test 1 — object `CosDocument`
> The document catalog dictionary shall include a MarkInfo dictionary with a
> Marked entry in it, whose value shall be true
### 6.8.3.3 test 1 — object `PDDocument`
> The logical structure of the conforming file shall be described by a structure
> hierarchy rooted in the StructTreeRoot entry of the document catalog dictionary
PDF/A-1**a** is the *accessible* conformance level and requires a tagged PDF.
`Spire.XLS` accepts `Pdf_A_1_A`, stamps the claim into the metadata, and then
emits an **untagged** document with no `StructTreeRoot` and no `MarkInfo`.
Note that `Spire.Doc` gets this right — its PDF/A-1a output validates 11/11.
The two libraries behave inconsistently for the same requested level.
---
## Impact
For archival use under ISO 19005 the practical consequence is that **only
PDF/A-1b is usable with Spire** — Spire.Doc additionally 1a. Any workflow that
requires PDF/A-2 or PDF/A-3 (common for long-term archives and for embedding
source attachments) will produce files that fail conformance checking.
The failure mode is the problem as much as the failure: the API reports success,
the file declares the requested level, and nothing indicates non-compliance until
an external validator is run.
## Request
1. Fix the three font-level rules for PDF/A-2/3 in Spire.Doc: no zero/BOM code
points in `ToUnicode`, complete `CIDSet`, `ActualText` for PUA glyphs.
2. Emit tagged output for `Pdf_A_1_A` in Spire.XLS, as Spire.Doc already does.
3. Until then — and as good behaviour generally — please **fail loudly rather
than silently**: if a requested conformance level cannot be met, throw, or at
minimum do not write the conformance claim into the metadata.
## Reproduction
```java
Document doc = new Document();
doc.loadFromFile("SPOD.rtf");
ToPdfParameterList p = new ToPdfParameterList();
p.isEmbeddedAllFonts(true);
p.setPdfConformanceLevel(PdfConformanceLevel.Pdf_A_2_A);
doc.saveToFile("out-2a.pdf", p);
```
Then validate, e.g. with the veraPDF CLI, letting it auto-detect the flavour:
```
verapdf --format text out-2a.pdf
```
Test corpus and produced PDFs available on request. Environment: JDK 17
(Microsoft OpenJDK 17.0.18 on Windows 11, Eclipse Adoptium 17.0.20.1 on Ubuntu),
licence Developer OEM applied, no evaluation watermark present in any output.