ThreeMammals/Ocelot · error · FormatException
The ' ' value doesn't include any digits, so it cannot be…
Error message
The '{timespan}' value doesn't include any digits, so it cannot be considered a number! What it means
RateLimitRule.ParseTimespan parses rate-limit period strings like '1s', '5m'. If the input string contains no digit characters at all, it throws FormatException because no numeric value can be extracted. The call chain is PeriodSpan/WaitSpan -> ParseTimespan, fed from the RateLimitOptions configuration.
Solutions
- Fix the configured value to include a number plus optional unit, e.g. '1s', '5m', '100ms'.
- Validate ocelot.json route rate-limit options before startup (RouteFluentValidator per the TODO).
- If values come from config providers/env vars, check the substituted value is non-empty and numeric.
- Wrap client creation in try/catch for FormatException to surface which route is misconfigured.
Example fix
// before
"RateLimitRule": { "Period": "s", "Limit": 10 }
// after
"RateLimitRule": { "Period": "1s", "Limit": 10 } Defensive patterns
Strategy: validation
Validate before calling
bool IsValidRateLimitPeriod(string p) =>
!string.IsNullOrEmpty(p) && p.Any(char.IsDigit);
// run before loading ocelot.json rate-limit rules Try / catch
try { var period = RateLimitRule.PeriodSpan(rule.Period); }
catch (FormatException ex) { Error($"Bad rate-limit period '{rule.Period}': {ex.Message}"); throw; } Prevention
- Always configure periods as number + unit, e.g. '1s', '5m', '100ms'
- Never leave Period as an empty string or placeholder
- Validate ocelot.json rate-limit fields at startup
- Lint configuration with the Ocelot schema in CI
When it happens
Trigger: A route's RateLimitRule Period or a client's Wait value is set to a string like 's', 'abc', '', or '.m' — no digits anywhere in the value.
Common situations: Typo in ocelot.json rate limiting config ('Period': 'second'); empty string from environment-variable substitution; deserialized default leaving a blank period.
Understand the failure class
Background: "invalid duration" / "failed to parse duration": why your timeout, interval, or TTL string is rejected and which formats each library accepts — this error's family across 32 libraries.
Related errors
- The ' ' timespan cannot be converted to TimeSpan due to an…
- ConfigurationRepositoryException(config.Errors)
AI-assisted analysis of ThreeMammals/Ocelot@d1f22d9304 (2026-09-12).
Data as JSON: /api/errors/01e16a237a4744f2.
Report an issue: GitHub.
Appendix: source
Thrown at src/Configuration/RateLimitRule.cs:67
/// <summary>
/// Parses a timespan string, such as "1ms", "1s", "1m", "1h", "1d".
/// </summary>
/// <remarks>Converts a string to milliseconds when the unit is missing or undefined, automatically applying the 'ms' unit.</remarks>
/// <param name="timespan">The string value with units: '1ms', '1s', '1m', '1h', '1d'.</param>
/// <returns>A <see cref="TimeSpan"/> value.</returns>
/// <exception cref="FormatException">If the value is not a number, or the unit of value cannot be determined.</exception>
public static TimeSpan ParseTimespan(string timespan)
{
if (string.IsNullOrWhiteSpace(timespan))
{
return TimeSpan.Zero;
}
if (!timespan.Any(char.IsDigit))
{
// TODO: Make sense to have validation in src/Ocelot/Configuration/Validator/RouteFluentValidator
throw new FormatException($"The '{timespan}' value doesn't include any digits, so it cannot be considered a number!");
}
string val = timespan.Trim();
int pos = val.Length;
while (--pos >= 0 && !char.IsDigit(val[pos]) && val[pos] != DecimalSeparator)
{
}
string floating = val[..++pos], unit = val[pos..];
double value = Math.Abs(double.Parse(floating)); // negative values should be disallowed as they could cause everything to malfunction; TODO: Make sense to have validation in src/Ocelot/Configuration/Validator/RouteFluentValidator
return unit.ToLower() switch
{
"d" => TimeSpan.FromDays(value),
"h" => TimeSpan.FromHours(value),
"m" => TimeSpan.FromMinutes(value),
"s" => TimeSpan.FromSeconds(value),
"ms" => TimeSpan.FromMilliseconds(value),
"" => TimeSpan.FromMilliseconds(value), // an unknown unit defaults to milliseconds as the ms unit
View on GitHub (pinned to d1f22d9304)