{"action":"created","issue":{"url":"https://api.github.com/repos/aspnet/Mvc/issues/3280","labels_url":"https://api.github.com/repos/aspnet/Mvc/issues/3280/labels{/name}","comments_url":"https://api.github.com/repos/aspnet/Mvc/issues/3280/comments","events_url":"https://api.github.com/repos/aspnet/Mvc/issues/3280/events","html_url":"https://github.com/aspnet/Mvc/issues/3280","id":110272345,"number":3280,"title":"Unhelpful exception message when validation message is empty","user":{"login":"ryanbrandenburg","id":14987221,"avatar_url":"https://avatars.githubusercontent.com/u/14987221?v=3","gravatar_id":"","url":"https://api.github.com/users/ryanbrandenburg","html_url":"https://github.com/ryanbrandenburg","followers_url":"https://api.github.com/users/ryanbrandenburg/followers","following_url":"https://api.github.com/users/ryanbrandenburg/following{/other_user}","gists_url":"https://api.github.com/users/ryanbrandenburg/gists{/gist_id}","starred_url":"https://api.github.com/users/ryanbrandenburg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ryanbrandenburg/subscriptions","organizations_url":"https://api.github.com/users/ryanbrandenburg/orgs","repos_url":"https://api.github.com/users/ryanbrandenburg/repos","events_url":"https://api.github.com/users/ryanbrandenburg/events{/privacy}","received_events_url":"https://api.github.com/users/ryanbrandenburg/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"milestone":null,"comments":1,"created_at":"2015-10-07T17:05:59Z","updated_at":"2015-10-08T01:40:25Z","closed_at":"2015-10-08T01:40:25Z","body":"The exception message when you give an empty string as a validation ErrorMessage could be more helpful, as it's not immediately clear that the action item here is \"Empty strings not allowed, give a real string.\"\r\n\r\nOffending Model:\r\n```C#\r\npublic class Post\r\n{\r\n    [Required]\r\n    public string Title { get; set; }\r\n    [Required, MinLength(1, ErrorMessage = \"\")]\r\n    public string Content { get; set; }\r\n}\r\n```\r\n\r\nOffending Form Group:\r\n```HTML\r\n<div class=\"form-group\">\r\n    @Html.LabelFor(model => model.Title, htmlAttributes: new { @class= \"control-label col-md-2\"})\r\n     <div class=\"col-md-10\">\r\n         @Html.EditorFor(model => model.Title, new { htmlAttributes= new { @class = \"control-label col-md-2\" } })\r\n         @Html.ValidationMessageFor(model => model.Title, \"\", new { @class= \"text-danger\"})\r\n     </div>\r\n</div>\r\n```\r\n\r\nError Message:\r\n`InvalidOperationException: Either ErrorMessageString or ErrorMessageResourceName must be set, but not both.`\r\n\r\nStacktrace:\r\n```\r\nSystem.ComponentModel.DataAnnotations.ValidationAttribute.SetupResourceAccessor()\r\nSystem.ComponentModel.DataAnnotations.ValidationAttribute.get_ErrorMessageString()\r\nSystem.ComponentModel.DataAnnotations.MinLengthAttribute.FormatErrorMessage(String name)\r\nMicrosoft.AspNet.Mvc.ModelBinding.Validation.DataAnnotationsClientModelValidator`1.GetErrorMessage(ModelMetadata modelMetadata)\r\nMicrosoft.AspNet.Mvc.ModelBinding.Validation.MinLengthAttributeAdapter.GetClientValidationRules(ClientModelValidationContext context)\r\nMicrosoft.AspNet.Mvc.ViewFeatures.DefaultHtmlGenerator.<>c__DisplayClass31_0.<GetClientValidationRules>b__0(IClientModelValidator v)\r\nSystem.Linq.Enumerable.<SelectManyIterator>d__1`2.MoveNext()\r\nMicrosoft.AspNet.Mvc.ViewFeatures.UnobtrusiveValidationAttributesGenerator.GetValidationAttributes(IEnumerable`1 clientRules)\r\nMicrosoft.AspNet.Mvc.ViewFeatures.DefaultHtmlGenerator.GetValidationAttributes(ViewContext viewContext, ModelExplorer modelExplorer, String expression)\r\nMicrosoft.AspNet.Mvc.ViewFeatures.DefaultHtmlGenerator.GenerateInput(ViewContext viewContext, InputType inputType, ModelExplorer modelExplorer, String expression, Object value, Boolean useViewData, Boolean isChecked, Boolean setId, Boolean isExplicitValue, String format, IDictionary`2 htmlAttributes)\r\nMicrosoft.AspNet.Mvc.ViewFeatures.DefaultHtmlGenerator.GenerateTextBox(ViewContext viewContext, ModelExplorer modelExplorer, String expression, Object value, String format, Object htmlAttributes)\r\nMicrosoft.AspNet.Mvc.ViewFeatures.HtmlHelper.GenerateTextBox(ModelExplorer modelExplorer, String expression, Object value, String format, Object htmlAttributes)\r\nMicrosoft.AspNet.Mvc.ViewFeatures.HtmlHelper.TextBox(String expression, Object value, String format, Object htmlAttributes)\r\nMicrosoft.AspNet.Mvc.ViewFeatures.DefaultEditorTemplates.GenerateTextBox(IHtmlHelper htmlHelper, String inputType)\r\nMicrosoft.AspNet.Mvc.ViewFeatures.DefaultEditorTemplates.StringTemplate(IHtmlHelper htmlHelper)\r\nMicrosoft.AspNet.Mvc.ViewFeatures.Internal.TemplateRenderer.Render()\r\nMicrosoft.AspNet.Mvc.ViewFeatures.Internal.TemplateBuilder.Build()\r\nMicrosoft.AspNet.Mvc.ViewFeatures.HtmlHelper.GenerateEditor(ModelExplorer modelExplorer, String htmlFieldName, String templateName, Object additionalViewData)\r\nMicrosoft.AspNet.Mvc.ViewFeatures.HtmlHelper`1.EditorFor[TResult](Expression`1 expression, String templateName, String htmlFieldName, Object additionalViewData)\r\nMicrosoft.AspNet.Mvc.Rendering.HtmlHelperEditorExtensions.EditorFor[TModel,TResult](IHtmlHelper`1 htmlHelper, Expression`1 expression, Object additionalViewData)\r\nAsp.ASPV__Views_Post_Create_cshtml.<ExecuteAsync>d__17.MoveNext() in Create.cshtml\r\n                @Html.EditorFor(model => model.Content, new { htmlAttributes = new { @class = \"control-label col-md-2\" } })\r\n--- End of stack trace from previous location where exception was thrown ---\r\nSystem.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\nSystem.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\nMicrosoft.AspNet.Mvc.Razor.RazorView.<RenderPageAsync>d__17.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\nSystem.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\nSystem.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\nMicrosoft.AspNet.Mvc.Razor.RazorView.<RenderAsync>d__16.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\nSystem.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\nSystem.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\nMicrosoft.AspNet.Mvc.ViewFeatures.ViewExecutor.<ExecuteAsync>d__1.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\nSystem.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\nSystem.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\nMicrosoft.AspNet.Mvc.ViewResult.<ExecuteResultAsync>d__24.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\nSystem.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\nSystem.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\nMicrosoft.AspNet.Mvc.Controllers.FilterActionInvoker.<InvokeResultAsync>d__53.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\nSystem.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\nSystem.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\nSystem.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)\r\nMicrosoft.AspNet.Mvc.Controllers.FilterActionInvoker.<InvokeResultFilterAsync>d__52.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\nMicrosoft.AspNet.Mvc.Controllers.FilterActionInvoker.<InvokeAllResultFiltersAsync>d__51.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\nSystem.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\nSystem.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\nSystem.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)\r\nMicrosoft.AspNet.Mvc.Controllers.FilterActionInvoker.<InvokeResourceFilterAsync>d__46.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\nMicrosoft.AspNet.Mvc.Controllers.FilterActionInvoker.<InvokeAsync>d__41.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\nSystem.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\nSystem.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\nMicrosoft.AspNet.Mvc.Infrastructure.MvcRouteHandler.<RouteAsync>d__6.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\nSystem.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\nSystem.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\nMicrosoft.AspNet.Mvc.Routing.InnerAttributeRoute.<RouteAsync>d__10.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\nSystem.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\nSystem.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\nMicrosoft.AspNet.Routing.RouteCollection.<RouteAsync>d__9.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\nSystem.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\nSystem.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\nMicrosoft.AspNet.Builder.RouterMiddleware.<Invoke>d__4.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\nSystem.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\nSystem.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\nMicrosoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\nMicrosoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\nSystem.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\nSystem.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\nMicrosoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\nMicrosoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\nSystem.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\nSystem.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\nMicrosoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\nMicrosoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\nSystem.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\nSystem.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\nMicrosoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\nMicrosoft.AspNet.Authentication.AuthenticationMiddleware`1.<Invoke>d__18.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\nSystem.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\nSystem.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\nMicrosoft.AspNet.Diagnostics.Entity.DatabaseErrorPageMiddleware.<Invoke>d__6.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\nMicrosoft.AspNet.Diagnostics.Entity.DatabaseErrorPageMiddleware.<Invoke>d__6.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\nSystem.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\nSystem.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\nMicrosoft.AspNet.Diagnostics.DeveloperExceptionPageMiddleware.<Invoke>d__6.MoveNext()\r\n```"},"comment":{"url":"https://api.github.com/repos/aspnet/Mvc/issues/comments/146390046","html_url":"https://github.com/aspnet/Mvc/issues/3280#issuecomment-146390046","issue_url":"https://api.github.com/repos/aspnet/Mvc/issues/3280","id":146390046,"user":{"login":"dougbu","id":6431421,"avatar_url":"https://avatars.githubusercontent.com/u/6431421?v=3","gravatar_id":"","url":"https://api.github.com/users/dougbu","html_url":"https://github.com/dougbu","followers_url":"https://api.github.com/users/dougbu/followers","following_url":"https://api.github.com/users/dougbu/following{/other_user}","gists_url":"https://api.github.com/users/dougbu/gists{/gist_id}","starred_url":"https://api.github.com/users/dougbu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dougbu/subscriptions","organizations_url":"https://api.github.com/users/dougbu/orgs","repos_url":"https://api.github.com/users/dougbu/repos","events_url":"https://api.github.com/users/dougbu/events{/privacy}","received_events_url":"https://api.github.com/users/dougbu/received_events","type":"User","site_admin":false},"created_at":"2015-10-08T01:40:25Z","updated_at":"2015-10-08T01:40:25Z","body":"@ryanbrandenburg this is not a MVC issue or even a DNX one. This `System.ComponentModel.DataAnnotations.ValidationAttribute` behaviour hasn't changed much since it was added in .NET 3.5. (`MinLengthAttribute` looks like it was added in .NET 4.5 but it inherits these checks.)\r\n\r\nAs the message says, you must set `ErrorMessage` or `ErrorMessageResourceName`. All it leaves out is \"... to a valid value i.e. not a `null` or empty string.\" But that's documented on MSDN. See for example the [docs for .NET 3.5](https://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.validationattribute.errormessage(v=vs.90).aspx) -- the `ArgumentException` condition in particular."}}