{"record":{"id":"2fa258cc77e04c46","repo":"ThreeMammals/Ocelot","slug":"the-timespan-timespan-cannot-be-converted-to-timespan-due-to","errorCode":null,"errorMessage":"The '{timespan}' timespan cannot be converted to TimeSpan due to an unknown '{unit}' unit!","messagePattern":"The '(.+?)' timespan cannot be converted to TimeSpan due to an unknown '(.+?)' unit!","errorType":"validation","errorClass":"FormatException","httpStatus":null,"severity":"error","filePath":"src/Configuration/RateLimitRule.cs","lineNumber":86,"sourceCode":"        }\r\n\r\n        string val = timespan.Trim();\r\n        int pos = val.Length;\r\n        while (--pos >= 0 && !char.IsDigit(val[pos]) && val[pos] != DecimalSeparator)\r\n        {\r\n        }\r\n\r\n        string floating = val[..++pos], unit = val[pos..];\r\n        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\r\n        return unit.ToLower() switch\r\n        {\r\n            \"d\" => TimeSpan.FromDays(value),\r\n            \"h\" => TimeSpan.FromHours(value),\r\n            \"m\" => TimeSpan.FromMinutes(value),\r\n            \"s\" => TimeSpan.FromSeconds(value),\r\n            \"ms\" => TimeSpan.FromMilliseconds(value),\r\n            \"\" => TimeSpan.FromMilliseconds(value), // an unknown unit defaults to milliseconds as the ms unit\r\n            _ => throw new FormatException($\"The '{timespan}' timespan cannot be converted to {nameof(TimeSpan)} due to an unknown '{unit}' unit!\"),\r\n        };\r\n    }\r\n\r\n    private static readonly char DecimalSeparator = new NumberFormatInfo().NumberDecimalSeparator[0];\r\n}\r\n","sourceCodeStart":68,"sourceCodeEnd":92,"githubUrl":"https://github.com/ThreeMammals/Ocelot/blob/d1f22d930430410bfd0233f5e9e4f92980cf7df0/src/Configuration/RateLimitRule.cs#L68-L92","documentation":"After extracting the numeric value, ParseTimespan maps the unit suffix (d, h, m, s, ms; empty = milliseconds) to a TimeSpan via a switch expression. An unrecognized unit suffix throws FormatException. This protects against typos like '1x' or '5sec'.","triggerScenarios":"A Period/Wait config value ends in a suffix outside {d,h,m,s,ms,'' }, e.g. '30sec', '2min', '1hr', '5M' (uppercase M is not accepted as minutes).","commonSituations":"Human-readable units typed into ocelot.json ('5min'); copy-pasted durations from other libraries; case sensitivity mistakes ('S' vs 's'); localization adding non-standard suffixes.","solutions":["Change the configured value to an accepted unit: d, h, m, s, ms, or no suffix (milliseconds), e.g. '5min' -> '5m'.","Remember parsing is case-sensitive: use lowercase units.","Add startup validation of rate-limit values so the error names the offending route early.","If you need richer units, extend the switch expression in RateLimitRule.ParseTimespan."],"exampleFix":"// before\n\"Period\": \"5min\"\n// after\n\"Period\": \"5m\"","handlingStrategy":"validation","validationCode":"static readonly string[] Units = { \"d\", \"h\", \"m\", \"s\", \"ms\", \"\" };\nbool HasKnownUnit(string p) {\n    int i = 0; while (i < p.Length && (char.IsDigit(p[i]) || p[i]=='.')) i++;\n    return Units.Contains(p.Substring(i));\n}","typeGuard":null,"tryCatchPattern":"try { var period = RateLimitRule.PeriodSpan(value); }\ncatch (FormatException ex) { Error($\"Unsupported duration unit in '{value}': {ex.Message}\"); throw; }","preventionTips":["Use only lowercase units: d, h, m, s, ms — or no suffix for milliseconds","Write '5min' as '5m', '30sec' as '30s'","Document accepted units wherever rate limits are configured","Add unit tests covering ParseTimespan suffix parsing"],"tags":["rate-limiting","format-exception","invalid-unit","timespan","configuration"],"backgroundTag":"invalid-duration-format","analyzedSha":"d1f22d930430410bfd0233f5e9e4f92980cf7df0","analyzedAt":"2026-09-12T13:50:06.067Z","contentChangedAt":"2026-09-12T13:50:06.067Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}