ErrLookup › Background articles › ArgumentException — when a .NET method rejects an argument that breaks its contract
ArgumentException — when a .NET method rejects an argument that breaks its contract
ArgumentException is the .NET exception thrown when a method receives an argument that is the right type but semantically invalid: an unrecognized enum token, a null where a value is required, an index past the valid range, or a name that collides with an existing one. Developers meet it at the call site, before any work begins, with a message that usually names the offending parameter and lists the valid values. Across the 2040 documented records spanning 75 repositories, it is the most common shape of fail-fast guard in the .NET ecosystem.
Distilled from 2,040 documented records across 75 repositories.
Background
System.ArgumentException is the .NET base class for a method argument that is the correct type but violates the method's semantic contract. Unlike NullReferenceException or IndexOutOfRangeException, which signal a bug the caller did not anticipate, ArgumentException is an intentional guard the library author placed at the method boundary. Every one of these 30 records is from a C#/.NET library, and in each case the throw happens on the first line of validation — before any structural change, before any side effect. HyperlinkUriValidator.RequireSafeScheme checks the URL scheme before writing the hyperlink (record 0); AudioFileWriter.Write checks the running byte count against the RIFF ceiling before each buffer flush (record 1); Job.Validate checks the type-method relationship before a job is enqueued (record 16).
The family exists as a fail-fast replacement for silent corruption. Multiple records state that the exception was introduced to kill a prior silent-accept behavior that produced broken output: the WAV writer guards against overflowing the unsigned 32-bit data-size field, which would produce an unreadable file; OfficeCLI's legend-position parser used to silently coerce unknown tokens to 'bottom', leaving the file contradictory with its success message (record 4); the defined-name collision check prevents Excel's 'found a problem' repair dialog (record 5); the boolean retype guard (record 24) prevents a stamping of t="b" onto text content that Excel rejects with error 0x800A03EC. The throw is a design decision: the author chose a clean, early exception over a late, confusing failure or a corrupt artifact.
From the caller's side the exception is deterministic and self-documenting. It fires on the specific call whose argument violates the contract — the Nth write that pushes the cumulative total past 4 GiB, the Set call whose narrowed source range leaves a pivot field index pointing past the new column count (record 2). The constructor takes both a message and a paramName, so the exception identifies which argument is at fault, and the message frequently enumerates the valid set verbatim: "Valid: top, bottom, left, right, topRight" (record 4); "Valid: sum, average, count, countNums, max, min, stdDev, var, none, custom" (record 9); "only http, https, mailto, ftp, ftps, sftp, news, tel, sms, file, about, and ppaction" (record 0). This makes ArgumentException one of the most actionable exception classes in .NET: the fix is usually stated in the message itself.
The family clusters into several distinct shapes across libraries. Allowlist guards reject tokens outside a known enumerated set — URI schemes, registry hive aliases, chart legend and label positions, totals-row functions, wallpaper styles. Capacity guards reject values that exceed a physical or format limit — the WAV 4 GiB ceiling, the Excel 1,048,576-row ceiling, array dimensions of zero or less. Consistency guards reject duplicates and type mismatches — defined-name collisions at the same scope, toolbar button ID conflicts, a Job whose declaring type does not match the method. Lookup guards reject references to unregistered targets — YARP policy names not in the DI dictionary (records 19, 25), workflow node IDs not in the steps map (record 14). Format guards reject content that does not match its declared form — image magic bytes disagreeing with the file extension (record 17), a ChannelId key not parseable as a Guid in N format (record 11). One record (29, Maui's BindableProperty) is an internal-consistency case where the coercion and validation callbacks disagree after a value is clamped. The behavior on edge cases is library-specific: some validators trim and case-normalize before matching (record 4's SchemaKeyNormalizer), others are case-sensitive and do not trim (record 3's registry hive parser, record 27's Enum.TryParse).
Common causes
- String token not in the allowed set.The most common shape across the family. A method expects one of a fixed set of enum aliases or scheme names and receives a token that matches none of them. The parser may be case-sensitive and may not trim whitespace (record 3's registry hive parser fails on a trailing space; record 27's Enum.TryParse fails on lowercase 'tiled'), or it may normalize first (record 4 strips dashes and lowercases). The message usually lists the accepted tokens, though some validators accept aliases not shown in the error text (record 9 advertises 'countNums' but also accepts 'avg', 'countnumbers', 'maximum', 'stdev', 'variance', 'label').
- Null, empty, or whitespace required argument.A required argument is missing entirely. Orleans' ConfigureEventHubConnection throws when the connection string is null, empty, or whitespace (record 7), typically because a configuration key was absent from appsettings or the environment. Orleans' BroadcastChannelWriter.Publish throws on line one when the ChannelId has no namespace (record 23), which happens when ChannelId.Create is called with a null first argument. The guard fires before any downstream processing.
- Index or count outside the valid range.A numeric argument exceeds a physical or format limit. OfficeCLI rejects row indices beyond Excel's 1,048,576-row ceiling (record 21) and pivot field indices that point past a narrowed source range (record 2). The WAV writer rejects the write whose cumulative byte count crosses 4 GiB (record 1). QuantConnect's ShareClassMeanReversionAlphaModel rejects any symbol count other than 2 (record 12), and Unity's CustomPreviewGenerator rejects non-positive width (record 13). The failing call is the one that crosses the boundary, even if the individual argument is small.
- Duplicate identifier or name collision.An identifier already exists at the same scope or in the same registry. OfficeCLI rejects a defined name whose (name, localSheetId) pair already exists (record 5); ImageGlass rejects a toolbar button ID that matches an existing entry case-insensitively (record 26); YARP's ServiceLookupHelper rejects two policies returning the same Name during dictionary construction (record 25). A same-named entry at a different scope is often legal — only exact (name, scope) collisions fail.
- Type mismatch or unsupported type at a dispatch boundary.An argument is the right base type but the wrong concrete type for the operation. Hangfire's GetHttpContext throws when the DashboardContext is not the AspNetCoreDashboardContext subclass (record 6); Hangfire's Job.Validate throws when the method's DeclaringType is not assignable to the specified job Type (record 16); Newtonsoft.Json's JsonConvert.ToString(object) throws on any non-primitive type because the switch has no case for it (record 15). These are type-safety guards that surface what would otherwise be an InvalidCastException at invocation time.
- Unresolvable reference to an unregistered target.A configuration or API call names an entity that was never registered. YARP throws when a cluster references a LoadBalancingPolicy, SessionAffinity policy, or health-check policy whose name is not in the frozen lookup dictionary (record 19). Semantic Kernel's WorkflowBuilder throws when an orchestration edge's listen_for.from references a step Id that was never added (record 14). The guard fires at construction or request time, before the missing target is accessed.
- Content or format mismatch.An argument's declared form does not match its actual content. OfficeCLI rejects an image whose extension says PNG but whose magic bytes are JPEG FF D8 FF (record 17). Orleans rejects a ChannelId key that cannot be parsed as a Guid in N format for a Guid-keyed subscriber grain (record 11). OfficeCLI rejects a boolean retype on existing cell text that is not bool-convertible (record 24), a trendline flag value outside the eight accepted boolean tokens (record 18), and a cross-workbook reference syntax that would produce a silently broken defined name (record 22). Humanizr rejects a number word not in the locale's vocabulary (record 28).
- Internal callback or constraint inconsistency.A rarer shape where the library's own internal invariants disagree. Maui's BindableProperty throws when CoerceValue returns a value that ValidateValue still rejects (record 29), meaning the clamping logic and the validation predicate are out of sync. This is not a caller error in the usual sense — it signals a misconfiguration in the property's registered callbacks.
What usually fixes it
- Read the message and paramName first. ArgumentException is one of the most self-documenting exceptions in .NET: the message frequently enumerates the valid token set verbatim and the paramName identifies which argument is at fault. The shortest path to a fix is usually in the error text itself — but cross-check the source, because some validators accept aliases not listed in the message.
- Validate and normalize upstream before the library call. Trim whitespace, normalize casing, and pre-filter against the accepted set at the caller or input boundary. A large fraction of failures are casing or whitespace artifacts: a trailing space on a registry hive string (record 3), lowercase input to a case-sensitive Enum.TryParse (record 27), or a boolean token with stray casing (record 18). Normalizing client-side prevents the throw entirely.
- Prefer the non-throwing variant when one exists. Several records point to a Try* or Is* predicate on the same API: OfficeCLI's IsSafeScheme (record 0), Humanizr's TryToNumber (record 28), and the various TryGetValue overloads. These let you handle invalid input through control flow rather than exception handling.
- Centralize construction of objects with interdependent constraints in a single factory. For ChannelId (always pass a non-empty namespace, record 23), CustomPreviewGenerationSettings (all five dimensions positive, record 13), or alpha-model symbol arrays (exactly two elements, record 12), one construction site that asserts all invariants prevents the scattered calls that forget a field.
- Register targets before referencing them and dedupe before adding. For lookup failures (records 14, 19), ensure every referenced policy name or step Id has a matching registration in the DI container or steps map. For collision failures (records 5, 26, 25), check for an existing entry — case-insensitively, at the same scope — before adding, or make add operations idempotent via remove-then-add.
- Keep type references consistent with the concrete type the method expects. Derive the Job type from method.DeclaringType rather than hard-coding (record 16); construct AspNetCoreDashboardContext rather than the base DashboardContext in tests (record 6); use the strongly-typed overload (ChannelId.Create with a Guid key, JsonConvert.ToString(DateTime)) to avoid the object-dispatch fallthrough (records 11, 15).
Documented occurrences
- Invalid {contextKey} URL scheme '{scheme}:': only http, https, mailto, ftp, ftps, sftp, news, tel, sms, file, about, and ppaction targets are accepted. javascript:, data:, vbscript:, and similar schemes are rejected to prevent click-bait redirection in shared documents.(iOfficeAI/OfficeCLI)
- WAV file too large(MathewSachin/Captura)
- {axis} field '{fieldRef}' (index {idx}) is out of range after source narrowing to {newFieldCount} column(s). Restate {axis}= in the same Set call to drop or reassign it.(iOfficeAI/OfficeCLI)
- Invalid registry hive string.(mRemoteNG/mRemoteNG)
- Invalid legend position '{value}'. Valid: none, top, bottom, left, right, topRight (or use 'none'/'false' to hide the legend).(iOfficeAI/OfficeCLI)
- Defined name '{nrName}' already exists in workbook scope; remove it before adding a new one or pick a different name.(iOfficeAI/OfficeCLI)
- Context argument should be of type `AspNetCoreDashboardContext`!(HangfireIO/Hangfire)
- A non-null, non-empty value must be provided.(dotnet/orleans)
- Unknown label position '{value}'. Valid: center, insideEnd, outsideEnd, insideBase, top, bottom, left, right, bestFit.(iOfficeAI/OfficeCLI)
- Unknown totals-row function '{tok}'. Valid: sum, average, count, countNums, max, min, stdDev, var, none, custom.(iOfficeAI/OfficeCLI)
- Cannot remove the default theme pack.(d2phap/ImageGlass)
- streamId(dotnet/orleans)
- ShareClassMeanReversionAlphaModel: symbols parameter must contain 2 elements(QuantConnect/Lean)
- Width should be larger than 0(CoplayDev/unity-mcp)
- An orchestration is referencing a node with Id `{listenCondition.From}` that does not exist.(microsoft/semantic-kernel)
- Unsupported type: {0}. Use the JsonSerializer class to get the object's JSON representation.(JamesNK/Newtonsoft.Json)
- The type `{method.DeclaringType}` must be derived from the `{type}` type.(HangfireIO/Hangfire)
- Image file '{path}' has extension .{ext} but magic bytes indicate {ContentTypeName(sniffed)}. Rename or convert the file.(iOfficeAI/OfficeCLI)
- {fullKey}: expected boolean (true/false/1/0/yes/no/on/off), got '{value}'.(iOfficeAI/OfficeCLI)
- No {typeof(T)} was found for the id '{lookup}'.(dotnet/yarp)
…and 2,020 more across the corpus — use search.
Honest provenance: generated on 2026-08-13 from AI-assisted analysis of the linked records. See how records are made.