dotnet/wpf · error · System.Xml.XmlException
SR.RelationshipTransformNotFollowedByCanonicalizationTransfo…
Error message
SR.RelationshipTransformNotFollowedByCanonicalizationTransform
What it means
Per the OPC spec, a Relationship Transform must be immediately followed by a canonicalization transform. When a Relationship transform was found but no canonicalization transform was appended after it (transform count unchanged since the Relationship entry), the parser throws RelationshipTransformNotFollowedByCanonicalizationTransform.
Solutions
- Append a canonicalization Transform (e.g. http://www.w3.org/2001/10/xml-exc-c14n#) immediately after the Relationship Transform and re-sign
- Re-sign the package with PackageDigitalSignatureManager, which emits the required transform pair
- Update the signing tool to the OPC-compliant transform ordering (Relationship then C14N)
- Validate manifest transform order against the OPC spec before distribution
Example fix
// before <Transforms> <Transform Algorithm="http://schemas.openxmlformats.org/package/2006/RelationshipTransform"/> </Transforms> // after <Transforms> <Transform Algorithm="http://schemas.openxmlformats.org/package/2006/RelationshipTransform"/> <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/> </Transforms>
Defensive patterns
Strategy: validation
Validate before calling
const string relNs = "http://schemas.openxmlformats.org/package/2006/RelationshipTransform";
var c14nSet = new HashSet<string> { "http://www.w3.org/2001/10/xml-exc-c14n#" };
bool ordered = doc.Descendants(ds + "Transforms").All(t =>
{
var list = t.Elements(ds + "Transform").Select(x => (string)x.Attribute("Algorithm")).ToList();
for (int i = 0; i < list.Count; i++)
if (list[i] == relNs && (i + 1 >= list.Count || !c14nSet.Contains(list[i + 1])))
return false;
return true;
});
if (!ordered) throw new InvalidDataException("Relationship Transform must be followed by canonicalization"); Try / catch
try
{
sigManager.VerifySignatures(true);
}
catch (XmlException ex) when (ex.Message.Contains("Canonicalization"))
{
// wrong transform order: re-sign with Relationship + C14N pair
} Prevention
- Always emit Relationship Transform followed immediately by a canonicalization Transform
- Use PackageDigitalSignatureManager for signing to get correct ordering
- Validate transform ordering against the OPC spec before shipping packages
- Keep signing SDKs updated to OPC-compliant behavior
When it happens
Trigger: Verify on a signature whose Reference contains a Relationship Transform as the last (or only) transform, with no canonicalization transform following it.
Common situations: Signers implementing an older or partial interpretation of the OPC signature profile; manually assembled manifests omitting the required trailing C14N transform; migrated signatures from other packaging SDKs.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- SR.MultipleRelationshipTransformsFound
- SR.RequiredXmlAttributeMissing (uri)
- SR.XmlSignatureParseError
- SR.PackageSignatureObjectTagRequired
- SR.PackageSpecificReferenceTagMustBeUnique
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/caa12520501d3b93.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/MS/Internal/IO/Packaging/XmlSignatureManifest.cs:394
continue; // success
}
else
throw new InvalidOperationException(SR.UnsupportedTransformAlgorithm);
}
}
}
throw new XmlException(SR.XmlSignatureParseError);
}
if (transforms.Count == 0)
throw new XmlException(SR.XmlSignatureParseError);
//If we found another transform after the Relationship transform, it will be validated earlier
//in this method to make sure that its a supported xml canonicalization algorithm and so we can
//simplify this test condition - As per the OPC spec - Relationship transform must be followed
//by a canonicalization algorithm.
if (relationshipTransformFound && (transforms.Count == transformsCountWhenRelationshipTransformFound))
throw new XmlException(SR.RelationshipTransformNotFollowedByCanonicalizationTransform);
return transforms;
}
/// <summary>
/// Parse the Relationship-specific Transform
/// </summary>
/// <param name="reader"></param>
/// <param name="partUri"></param>
/// <param name="relationshipSelectors">may be allocated but will never be empty</param>
private static void ParseRelationshipsTransform(XmlReader reader, Uri partUri, ref List<PackageRelationshipSelector> relationshipSelectors)
{
Uri owningPartUri = System.IO.Packaging.PackUriHelper.GetSourcePartUriFromRelationshipPartUri(partUri);
// find all of the Relationship tags of form:
// <RelationshipReference SourceId="abc123" />
// or
// <RelationshipsGroupReference SourceType="reference-type-of-the-week" />View on GitHub (pinned to 81131a70a4)