Hello. The following output is admittedly a result with Claude Code but I did try to whittle out as much of the usual AI fluff to hopefully make this actually usable. I did, however, go through quite a bit of testing with it locally, reproducing the error with a local instance of Aspose.Words. Unfortunately, I can’t share any files (reasons stated below in the AI output) but I will follow up shortly and attach some relevant logs in a separate file.
Thanks in advance.
Product: Aspose.Words Cloud (self-hosted Docker deployment, docker.io/aspose/words-cloud:26.7)
Version: 26.7, the current release. Reproduced locally and running in our production deployment.
Client SDK: aspose_words_cloud Ruby gem 25.4
Endpoint: PUT /v4.0/words/online/put/compareDocument (compare_document_online)
Attachment: aspose-compare-nre-logs.txt
Summary
compareDocument returns HTTP 500 with a bare .NET null-reference error for certain pairs of real-world documents:
{"Error":{"Message":"Object reference not set to an instance of an object."},"RequestId":"..."}
Container logs show the failure originates from Aspose.Words.Cloud.WebApp.Filters.CoreResultExceptionFilter and resolves to two distinct null-deref sites inside the comparison engine.
Variant A, reached through table comparison:
System.NullReferenceException: Object reference not set to an instance of an object.
at X9.b(Node d)
at h9.p9iFQ(Char d)
at p9.p(Int32 d)
at p9.K(r9 d)
at p9.X()
at h9.O()
at R9.t(Row d, Row v, T9 c)
at W9.c(Table d, Table v, T9 c)
at m9.n()
at h9.O()
at i9.t()
at i9.c(Document d, Document v, CompareOptions c)
at Aspose.Words.Cloud.DocumentActions.Compare.Model.CompareService..MoveNext()
Variant B, reached directly from document comparison:
System.NullReferenceException: Object reference not set to an instance of an object.
at h9.p9iFQ(Char d)
at p9.p(Int32 d)
at p9.K(r9 d)
at p9.X()
at h9.O()
at i9.t()
at i9.c(Document d, Document v, CompareOptions c)
at Aspose.Words.Cloud.DocumentActions.Compare.Model.CompareService..MoveNext()
Both variants share the inner call chain h9.O() → p9.X() → p9.K(r9) → p9.p(Int32) → h9.p9iFQ(Char). Variant A is reached via W9.c(Table, Table, T9) → R9.t(Row, Row, T9) and throws in X9.b(Node). Variant B is reached directly from i9.c(Document, Document, CompareOptions) and throws in h9.p9iFQ(Char).
The stack traces are not present in the API response, only in the container logs, which is where the detail below comes from.
Observed frequency
Over the two-week window we retain traces for, this error occurred on 5 separate days, with a peak of approximately 40 failed requests in a single day, spread across 6 different end users. Document comparison is a core workflow in our product, so the failures are user-visible.
Request parameters
Reproduces with the following CompareOptions, which are our production settings:
{
"Author": "<user name>",
"CompareOptions": {
"AcceptAllRevisionsBeforeComparison": true,
"Granularity": "WordLevel",
"IgnoreFormatting": true,
"IgnoreHeadersAndFooters": true
}
}
Both the document part and the FileReference part are .docx. The failure reproduces on the raw uploaded files and also after our normal preprocessing (deleteMacros then saveAs docx), so no preprocessing is required to trigger it.
What we determined
We have 6 real document pairs taken from production failures. 5 of them reproduce 100% deterministically on a local 26.7 instance. Findings from bisecting them:
1. Two distinct null-deref sites in the comparison engine
Our 5 reproducing pairs split 4/1 across the two stack traces above, and the split correlates exactly with the two marker types in item 2. The 4 comment-range cases all produce Variant A, the bookmark case produces Variant B.
One observation we cannot account for: Variant B contains no table frames, yet IgnoreTables: true still prevents it.
2. The trigger is a range marker overlapping table content
Programmatically stripping all w:bookmarkStart / w:bookmarkEnd and w:commentRangeStart / w:commentRangeEnd / w:commentReference elements from both documents clears all 5 pairs. Three shapes observed:
| Pairs | Marker | Position | Trace |
|---|---|---|---|
| 3 | w:commentRangeStart/End pair |
wholly inside a table cell, in the FileReference document |
A |
| 1 | w:commentRangeStart inside a table, with its matching w:commentRangeEnd as a direct child of w:body after the table, so the range straddles the table boundary |
FileReference document |
A |
| 1 | w:bookmarkStart/End pair spanning body[0..83] of 85 body children, crossing two tables |
document part |
B |
Stripping only comment markers clears 4 of 5. Stripping only bookmarks clears the remaining 1.
3. It is asymmetric
Swapping which file is the document part and which is the FileReference changes the outcome. One direction throws, the other returns a valid result.
4. Merged or ragged cells are not required
The simplest failing pair is a single 1-row, 3-cell table on each side, with no revisions, no merged cells, and no bookmarks. Only the straddling comment range described above.
5. Minimal reduction
Automated delta-debugging of that pair reduced it to:
documentpart: one table, 1 row, 3 cellsFileReferencepart: the same table, followed by a body-levelw:commentRangeEnd, followed by an emptyw:p
6. A synthetic reconstruction did not reproduce
We built a document pair from scratch matching the structure in item 5, and it did not reproduce. Something about the surrounding content alignment appears to matter, so the structural description above may not be sufficient on its own to trigger the fault.
Workaround matrix (5 failing pairs)
| Option | Pairs cleared |
|---|---|
IgnoreTables: true |
5 / 5 |
IgnoreComments: true |
4 / 5 |
Granularity: "CharLevel" |
2 / 5 |
Granularity: "CharLevel" plus IgnoreComments: true |
4 / 5 |
Toggling AcceptAllRevisionsBeforeComparison, IgnoreFormatting, IgnoreHeadersAndFooters, IgnoreFields, IgnoreFootnotes, IgnoreTextboxes, and IgnoreCaseChanges has no effect on any pair.
Only IgnoreTables clears all cases. We have not adopted it, since suppressing table comparison would mean edits inside tables stop appearing as tracked changes with no indication to the user.
Environment note
Our local reproduction runs the linux/amd64 image under emulation on Apple silicon. This is not an emulation artifact. The identical error occurs in our production Kubernetes cluster on native linux/amd64, on the same 26.7 build.
On sample documents
We cannot share the affected documents. They are confidential client legal agreements and we are not able to transmit them, in whole, in part, or in derived or redacted form, to any third party.
We can help in these ways instead:
- Run any instrumented or debug build you provide against the documents in our own environment and return stack traces, logs, or diagnostic output.
- Run additional experiments you specify, such as option combinations, structural mutations, or other endpoints, and report results.
- Answer detailed structural questions about the documents’ OOXML.
We can also attach complete container logs for every failing request. We have verified these contain no document content, file names, or client-identifying strings, only ASP.NET framework diagnostics and the stack traces above, so they are shareable without restriction. See aspose-compare-nre-logs.txt.