astral-sh/ruff · error
invalid micro version: {micro}
Error message
invalid micro version: {micro} What it means
The UP036 (outdated sys.version_info block) rule compares a `sys.version_info` tuple against the target Python version. When parsing the comparison, the third (micro) element must be an integer literal; a non-integer literal (or unresolvable value) makes the comparison undecidable, so the rule bails.
Source
Thrown at crates/ruff_linter/src/rules/pyupgrade/rules/outdated_version_block.rs:238
let (py_major, py_minor) = py_version.as_tuple();
match if_major.cmp(&py_major) {
Ordering::Less => Ok(true),
Ordering::Greater => Ok(false),
Ordering::Equal => {
let Some(if_minor) = check_version_iter.next() else {
return Ok(true);
};
let Some(if_minor) = if_minor.as_u8() else {
return Err(anyhow::anyhow!("invalid minor version: {if_minor}"));
};
let if_micro = match check_version_iter.next() {
None => None,
Some(micro) => match micro.as_u8() {
Some(micro) => Some(micro),
None => anyhow::bail!("invalid micro version: {micro}"),
},
};
Ok(if or_equal {
// Ex) `sys.version_info <= 3.8`. If Python 3.8 is the minimum supported version,
// the condition won't always evaluate to `false`, so we want to return `false`.
if_minor < py_minor
} else {
if let Some(if_micro) = if_micro {
// Ex) `sys.version_info < 3.8.3`
if_minor < py_minor || if_minor == py_minor && if_micro == 0
} else {
// Ex) `sys.version_info < 3.8`. If Python 3.8 is the minimum supported version,
// the condition _will_ always evaluate to `false`, so we want to return `true`.
if_minor <= py_minor
}
})
}View on GitHub (pinned to 15f3fe6b15)
Solutions
- Write the version comparison with plain integer literals: `sys.version_info < (3, 8)` or `(3, 8, 0)`
- Remove the computed/dynamic micro component so UP036 can evaluate the condition
- Rewrite the check using `sys.version_info >= (3, 8)` form with `if`/`else` blocks the rule can update
Example fix
# before
if sys.version_info < (3, 8, get_micro()):
legacy()
# after
if sys.version_info < (3, 8):
legacy() Defensive patterns
Strategy: validation
Validate before calling
# Ensure version tuples use plain integer literals:
if sys.version_info < (3, 8): # OK
...
if sys.version_info < (3, 8, f()): # breaks UP036 analysis
... Prevention
- Use integer literals in sys.version_info comparisons
- Omit the micro component when not needed
- Prefer (major, minor) tuples over (major, minor, micro) in version checks
When it happens
Trigger: `version_always_less_than` iterated the version tuple and found a micro component whose `as_u8()` returned None — e.g. `sys.version_info < (3, 8, 'x')`, a computed value like `(3, 8, micro)`, or a float micro — instead of an integer literal.
Common situations: Dynamically computed version tuples, non-literal or malformed version comparisons in vendored/legacy compatibility shims, or code migrated from other tooling.
Related errors
- Could not find the ruff binary in any of the following locat
- Expected a ty `File`, found a ruff `SourceFile`
- Expected Stmt::ImportFrom
- Expected ScopeKind::Function | ScopeKind::Lambda
- Expected Stmt::Import | Stmt::ImportFrom
AI-assisted analysis of astral-sh/ruff@15f3fe6b15 (2026-09-05).
Data as JSON: /api/errors/96daee72bdb08a03.
Report an issue: GitHub.