{"record":{"id":"7df528c1b3d0a56a","repo":"App-vNext/Polly","slug":"primarymessage-nvalidation-errors-n-error-error","errorCode":null,"errorMessage":"{PrimaryMessage}\\nValidation Errors:\\n{error.ErrorMessage}","messagePattern":"(.+?)\\\\nValidation Errors:\\\\n(.+?)","errorType":"validation","errorClass":"ValidationException","httpStatus":null,"severity":"error","filePath":"src/Polly.Core/Utils/ValidationHelper.cs","lineNumber":51,"sourceCode":"        var errors = new List<ValidationResult>();\n\n        lock (ValidatorLock)\n        {\n            valid = Validator.TryValidateObject(context.Instance, new(context.Instance), errors, true);\n        }\n\n        if (!valid)\n        {\n            var stringBuilder = new StringBuilder(context.PrimaryMessage);\n            stringBuilder.AppendLine();\n\n            stringBuilder.AppendLine(\"Validation Errors:\");\n            foreach (var error in errors)\n            {\n                stringBuilder.AppendLine(error.ErrorMessage);\n            }\n\n            throw new ValidationException(stringBuilder.ToString());\n        }\n    }\n}\n","sourceCodeStart":33,"sourceCodeEnd":55,"githubUrl":"https://github.com/App-vNext/Polly/blob/d0e46bdb1ee11ea50d0e4b6846d2633d6bc09bac/src/Polly.Core/Utils/ValidationHelper.cs#L33-L55","documentation":"ValidationHelper.ValidateObject runs data-annotations validation on an options object and, on failure, throws a ValidationException whose message is the primary message followed by each ValidationResult.ErrorMessage on its own line. This is the single funnel through which all Polly.Core strategy options are validated at Add*/Build time, so the thrown message is always '{primary}\\nValidation Errors:\\n{each error}'.","triggerScenarios":"Configuring any strategy options object with values that violate [Range]/[Required]/[RegularExpression] data annotations (e.g. RetryStrategyOptions.MaxRetryAttempts = -1, TimeoutStrategyOptions.Timeout = negative), then adding the strategy or building the pipeline.","commonSituations":"Configuration values bound from appsettings without validation; arithmetic that produces out-of-range numbers; copy-pasted options where a field was left at an invalid default; upgrading Polly and hitting newly-added constraints.","solutions":["Read each ErrorMessage line in the thrown ValidationException; it names the property and the constraint that failed.","Correct the offending option value to satisfy the annotation (range, required, regex) and rebuild.","Validate options eagerly after configuration binding using the same data-annotations validator, or configure via the DI options-validation pattern."],"exampleFix":"// before\nnew RetryStrategyOptions { MaxRetryAttempts = -1, Delay = TimeSpan.FromSeconds(-5) };\n\n// after\nnew RetryStrategyOptions { MaxRetryAttempts = 3, Delay = TimeSpan.FromSeconds(2) };","handlingStrategy":"validation","validationCode":"// Validate options eagerly before adding/building:\nvar ctx = new ValidationContext(options);\nvar results = new List<ValidationResult>();\nif (!Validator.TryValidateObject(options, ctx, results, true)) {\n    throw new ValidationException(string.Join(\"\\n\", results.Select(r => r.ErrorMessage)));\n}","typeGuard":null,"tryCatchPattern":"try { builder.AddRetry(retryOptions); }\ncatch (ValidationException ex) {\n    // ex.Message lists each failing property+constraint; fix and retry\n}","preventionTips":["Read every 'Validation Errors:' line; each names the property and the rule it broke.","Validate configuration-bound options at startup using data-annotations or the DI options-validation pattern.","Keep numeric/TimeSpan options inside their documented ranges."],"tags":["validation","options","data-annotations","configuration","polly-core"],"backgroundTag":null,"analyzedSha":"d0e46bdb1ee11ea50d0e4b6846d2633d6bc09bac","analyzedAt":"2026-08-13T16:36:01.959Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}