dotnet/wpf · error · ArgumentException
Can only countersign parts with Digital Signature…
Error message
Can only countersign parts with Digital Signature ContentType.
What it means
The Countersign(certificate, signatures) overload validates that every URI in the signatures list refers to a package part whose content type exactly equals the XML Digital Signature content type, throwing ArgumentException (SR.CanOnlyCounterSignSignatureParts) otherwise.
Solutions
- Only pass URIs obtained from PackageDigitalSignature.SignaturePart.Uri of existing signatures in this package
- Filter the list to parts whose ValidatedContentType matches the XmlDSig content type before calling
- Do not reuse the Sign(parts) argument lists for Countersign — they have different semantics
- Catch ArgumentException and log which URI failed the content-type check
Example fix
// before
mgr.Countersign(cert, new List<Uri> { docPartUri }); // wrong: content part, not a signature part
// after
var sigUris = mgr.Signatures.Select(s => s.SignaturePart.Uri).ToList();
mgr.Countersign(cert, sigUris); Defensive patterns
Strategy: validation
Validate before calling
foreach (Uri uri in signatures)
{
var part = package.GetPart(uri);
if (!part.ContentType.Equals("application/vnd.openxmlformats-package.digital-signature+xml", StringComparison.Ordinal))
throw new ArgumentException($"Part {uri} is not a digital signature part.");
} Type guard
bool IsSignaturePart(Package pkg, Uri uri) =>
pkg.PartExists(uri) &&
pkg.GetPart(uri).ContentType == "application/vnd.openxmlformats-package.digital-signature+xml"; Try / catch
try { manager.Countersign(certificate, signatures); }
catch (ArgumentException ex) { log.Error("Non-signature part passed to Countersign", ex); } Prevention
- Build the URI list from PackageDigitalSignature.SignaturePart.Uri only
- Remember Countersign takes signature part URIs, unlike Sign which takes content parts
- Validate part content types before invoking Countersign
When it happens
Trigger: Passing URIs of non-signature parts (documents, images, relationship parts) in the signatures collection to Countersign; passing URIs copied from a different package.
Common situations: Confusing Countersign's URI list with the list of parts to sign (Sign's semantics); hardcoded URIs that point at ordinary content parts; URIs from a package with different part naming conventions.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Cannot countersign an unsigned package.
- Duplicates not allowed - signature part already exists.
- Must specify an item to sign.
- PackagePart URI does not correspond to a FixedDocument.
- Parameter cannot be a zero-length string.
AI-assisted analysis of dotnet/wpf@81131a70a4 (2026-09-14).
Data as JSON: /api/errors/e24685b43289c123.
Report an issue: GitHub.
Appendix: source
Thrown at src/Microsoft.DotNet.Wpf/src/WindowsBase/System/IO/Packaging/PackageDigitalSignatureManager.cs:635
/// returned signature.</remarks>
/// <exception cref="InvalidOperationException">Cannot CounterSign an unsigned package.</exception>
/// <exception cref="ArgumentException">signatures must be non-empty and cannot refer to parts other than signature parts.</exception>
/// <exception cref="ArgumentNullException">Both arguments must be non-null.</exception>
public PackageDigitalSignature Countersign(X509Certificate certificate, IEnumerable<Uri> signatures)
{
ArgumentNullException.ThrowIfNull(certificate);
ArgumentNullException.ThrowIfNull(signatures);
// Counter-sign makes no sense if we are not already signed
if (!IsSigned)
throw new InvalidOperationException(SR.NoCounterSignUnsignedContainer);
// Restrict signatures to be actual signature part references
foreach (Uri uri in signatures)
{
PackagePart part = _container.GetPart(uri);
if (!part.ValidatedContentType().AreTypeAndSubTypeEqual(XmlDigitalSignatureProcessor.ContentType))
throw new ArgumentException(SR.Format(SR.CanOnlyCounterSignSignatureParts, signatures));
}
return Sign(signatures, certificate);
}
#endregion
/// <summary>
/// verify all signatures - calls verify on each signature
/// </summary>
/// <param name="exitOnFailure">true to exit on first failure - false to continue</param>
/// <remarks>register for invalid signature events</remarks>
public VerifyResult VerifySignatures(bool exitOnFailure)
{
VerifyResult result;
EnsureSignatures();
// signed?
if (_signatures.Count == 0)View on GitHub (pinned to 81131a70a4)