Skip to main content

Overview

NuGet.Services.Validation.Issues is a small, focused library that defines the concrete validation issue types reported when the NuGet pipeline rejects a package or symbol upload. Each issue carries a ValidationIssueCode (an integer enum) plus any structured contextual data needed to render a meaningful error message to the package author. The library targets both net472 and netstandard2.0, allowing it to be consumed by full-framework Gallery web services and .NET Standard validation worker processes alike.

Role in the System

Produced by validators

Signing, symbol, and policy validators create ValidationIssue instances and persist them (code + serialized JSON data) to the validation database.

Consumed by the Gallery

NuGetGallery reads persisted issue records and calls ValidationIssue.Deserialize to reconstruct typed objects for display on the package page.

Contract boundary

Sits between NuGet.Services.Contracts (which owns IValidationIssue and ValidationIssueCode) and any service that needs to produce or render rich error payloads.

Multi-framework shared library

Dual-targets net472 + netstandard2.0 so it can be referenced by both legacy ASP.NET Gallery code and modern worker services without forking.

Key Files and Classes

FileClass / TypePurpose
ValidationIssue.csValidationIssue (abstract)Base class; owns static singleton instances for no-data issues, the IssueCodeTypes dispatch map, and the Deserialize / Serialize methods.
NoDataValidationIssue.csNoDataValidationIssueSealed concrete type for all issue codes that carry no additional payload (e.g. PackageIsSigned, PackageIsZip64, all symbol error codes).
ClientSigningVerificationFailure.csClientSigningVerificationFailureCarries a ClientCode and ClientMessage forwarded verbatim from the NuGet client signing APIs; JSON-compact properties "c" and "m".
UnauthorizedCertificateFailure.csUnauthorizedCertificateFailureCarries the SHA-256 thumbprint of the certificate that was rejected; JSON-compact property "t".
ObsoleteTestingIssue.csObsoleteTestingIssue[Obsolete] type used only in tests; maps to ValidationIssueCode.ObsoleteTesting = 9999.
Properties/AssemblyInfo.csGrants InternalsVisibleTo for the test project; supports both signed and unsigned builds via #if SIGNED_BUILD.

Dependencies

NuGet Package References

PackagePurpose
Newtonsoft.JsonJSON serialization and deserialization of issue payload data via JsonConvert, [JsonProperty], and [JsonConstructor].

Internal Project References

ProjectWhat it provides
NuGet.Services.ContractsIValidationIssue interface and the ValidationIssueCode enum (integer codes 0–9 for package issues, 250–254 for symbol issues, 9999 for obsolete testing).

Issue Code Reference

CodeValueClassHas Payload
Unknown0NoDataValidationIssueNo
PackageIsSigned1NoDataValidationIssueNo
ClientSigningVerificationFailure2ClientSigningVerificationFailureYes — client code + message
PackageIsZip643NoDataValidationIssueNo
OnlyAuthorSignaturesSupported4NoDataValidationIssueNo
AuthorAndRepositoryCounterSignaturesNotSupported5NoDataValidationIssueNo
OnlySignatureFormatVersion1Supported6NoDataValidationIssueNo
AuthorCounterSignaturesNotSupported7NoDataValidationIssueNo
PackageIsNotSigned8NoDataValidationIssueNo
PackageIsSignedWithUnauthorizedCertificate9UnauthorizedCertificateFailureYes — SHA-256 thumbprint
SymbolErrorCode_ChecksumDoesNotMatch250NoDataValidationIssueNo
SymbolErrorCode_MatchingAssemblyNotFound251NoDataValidationIssueNo
SymbolErrorCode_PdbIsNotPortable252NoDataValidationIssueNo
SymbolErrorCode_SnupkgDoesNotContainSymbols253NoDataValidationIssueNo
SymbolErrorCode_SnupkgContainsEntriesNotSafeForExtraction254NoDataValidationIssueNo
ObsoleteTesting (obsolete)9999ObsoleteTestingIssueYes — test fields A, B

Serialization Pattern

Issues are persisted as two separate columns: the integer ValidationIssueCode and a JSON data string. The base class controls the full round-trip:
// Serialize (called by validators before writing to DB)
string json = issue.Serialize(); // => JsonConvert.SerializeObject(this)

// Deserialize (called by Gallery when reading from DB)
ValidationIssue issue = ValidationIssue.Deserialize(errorCode, json);
JSON property names on payload-bearing types are intentionally abbreviated to reduce storage size:
// ClientSigningVerificationFailure
{ "c": "NU3008", "m": "The package integrity check failed." }

// UnauthorizedCertificateFailure
{ "t": "A1B2C3...SHA256thumbprint..." }
NoDataValidationIssue is not constructed via JSON deserialization. Its instances are either the pre-built static singletons on ValidationIssue or constructed directly from an issue code. The IssueCodesWithNoData set acts as a fast-path gate in Deserialize to skip JSON parsing entirely for these codes.

Notable Patterns and Quirks

The dispatch map IssueCodeTypes only contains entries for issue codes that have a custom payload class. All other codes fall through to the IssueCodesWithNoData fast path or resolve to ValidationIssue.Unknown. Adding a new payload-bearing issue requires updating both IssueCodeTypes and ValidationIssueCode in the contracts project.
ValidationIssue.Deserialize silently swallows all JsonException errors and returns ValidationIssue.Unknown. This means a corrupt or schema-mismatched payload stored in the database will surface to users as a generic “unknown issue” rather than an exception. Validate payload schemas carefully before persisting.
ObsoleteTestingIssue and ValidationIssueCode.ObsoleteTesting are decorated with [Obsolete] and guarded by #pragma warning disable 618 at every reference site. They exist solely to enable round-trip serialization tests. Do not use them in production validation logic.
Symbol error codes are deliberately clustered in the 250–254 range (reserving 200–299 for future symbol issues) and map exclusively to NoDataValidationIssue. This makes it straightforward to detect all symbol-related failures with a simple range check on the integer code value.