Throwing exceptions in constructors in C# is fine, but a constructor should always create a valid object. I prefer to keep construction devoid of parsing. Parsing is inherently tricky, because you cannot trust the source of the data. Exceptions should be expected when parsing anything. The .NET stack already has a pattern to deal with this: Parse and TryParse.
While a monad is more idiomatic across languages, the [Try]Parse pattern is a long standing idiom for C#.
The constructor always takes data in the necessary pieces, and throws ArgumentXExceptions in the case invalid arguments are passed. The parse methods handle the parsing either by creating a valid object or throwing a FormatException.
var path = new NamePath(name, lastName); // throws Argument*Exception try { var path = NamePath.Parse("..."); // Use properly constructed path } catch (FormatException) { // Parse errors } if (NamePath.TryParse("...", out NamePath path)) { // User properly constructed NamePath as path variable } else { // Parse errors } This gives code authors some options with how to construct, parse and recover from errors. You'll see this pattern reflected in the native .NET types DateTime, int, decimal, etc. Your custom NamePath type will feel more natural to deal with along side the built-in types.