CNA-BUG-120: ContentManager::LoadXnbAssetUntyped refuses LZ4, which LoadXnbAsset<T> decodes

CNA snapshot 3b43bd86  ·  Known Issues › Current bugs  ·  source links pinned to 3b43bd86

✓

Evidence basis: source-verified at the pinned commit; tests exist (not executed for this page). Claims on this page were checked by reading the CNA source at commit 3b43bd86; unless a sentence says otherwise, nothing here was built or executed. Nothing on this page was executed unless the Evidence section says so.

The untyped decoder behind EffectMaterial external references throws for MonoGame LZ4 payloads that the typed load path decodes. Its missing compressed-header guard was fixed on 2026-10-22.

Identifier
CNA-BUG-120
Category
Bug
Subsystem
Content & XNB/CNB/CNJ
Status
Narrowed (partially fixed; describes only what survives)
Verified against
CNA 3b43bd86 (3b43bd8687ed46523d873f9bec4b32bd8481dcb5)
Severity
Medium (a triage suggestion, not a project priority)
Evidence basis
Source-verified: read at TARGET, not executed
Tests touching this area
Yes: see Current tests
Affected contract
ContentReader::ReadExternalReference() (untyped, CNAEXT; @throws ContentLoadException if the referenced compiled asset cannot be loaded) via ContentManager::LoadUntypedXnbReference / LoadXnbAssetUntyped

Expected behaviour

The untyped decoder decodes exactly like LoadXnbAsset<T> (ContentManager.hpp): MonoGame LZ4 payloads are decoded with DecompressXnbLz4Payload.

Actual behaviour at TARGET

The LZ4 branch of LoadXnbAssetUntyped (ContentManagerUntyped.cpp) throws ContentLoadException "uses MonoGame's Lz4 compression, which CNA does not yet support", while the typed decoder decodes it with DecompressXnbLz4Payload. So an EffectMaterial parameter that references an LZ4 texture fails, although Load<Texture2D> of the same file succeeds.

Source locations

Evidence

Checked by reading at 3b43bd86; not executed.

Narrowed at c6dec91f: 583af2a5e (CNA-DEMOS-ISSUE-039/045) moved the header checks into the shared ContentManager::ReadXnbHeader, which both loaders call: it refuses a totalLength outside [10, file size] and, for a compressed file, one below 14 before the size field is read, so the 10-13-byte over-read this entry also described is gone (ContentManagerXnbTest.UntypedCompressedHeaderRefusesBeforeReadingBeyondTheFile and UntypedExternalReferencesWrapEveryTruncatedHeader in ContentManagerXnbTests.cpp). The LZ4 refusal is unchanged.

Focused reproduction

Illustrative; not compiled.

// Content/params.xnb: an EffectMaterial / Dictionary<string, object> whose value is an\n// external reference to "tex"; Content/tex.xnb = tests/assets/xnb/monogame/windows/lz4/white-1.xnb.\nauto values = content.Load<std::map<std::string, std::any>>("params");\n// ContentLoadException "... Lz4 compression, which CNA does not yet support",\n// although content.Load<Graphics::Texture2D>("tex") decodes it.

Current tests

EffectMaterialContentTypeReaderTests.cpp (ExternalReferenceReaderPreservesReferencedTextureCubeConcreteType) uses an uncompressed fixture, and the new untyped header tests cover truncation only; no test sends an LZ4 asset through an untyped reference.

Regression test

A case beside the existing one: the same dictionary referencing the LZ4 fixture tests/assets/xnb/monogame/windows/lz4/white-1.xnb must yield a Texture2D.

Blast radius

Only untyped external references, which today means ExternalReferenceReader inside EffectMaterial parameter dictionaries. Typed references (ReadExternalReference<T>) and direct Load<T> calls use LoadXnbAsset<T> and are unaffected.

Workaround

Keep textures referenced by EffectMaterial content uncompressed or LZX-compressed.

The same subject is explained at several altitudes. These are the neighbouring pages at each one.

Known issues
Bug index