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

  1. Only pass URIs obtained from PackageDigitalSignature.SignaturePart.Uri of existing signatures in this package
  2. Filter the list to parts whose ValidatedContentType matches the XmlDSig content type before calling
  3. Do not reuse the Sign(parts) argument lists for Countersign — they have different semantics
  4. 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

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


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)