python/cpython · error · ValueError
unconverted data remains: %s
Error message
unconverted data remains: %s
What it means
The format regex matched a prefix of the input but data_string is longer than what the format covers — len(data_string) != found.end() with no %:z colon case. The ValueError reports the leftover suffix (rest = data_string[found.end():]).
Source
Thrown at Lib/_strptime.py:587
raise ValueError("'%s' is a bad directive in format '%s'" %
(bad_directive, format)) from None
_regex_cache[format] = format_regex
found = format_regex.match(data_string)
if not found:
raise ValueError("time data %r does not match format %r" %
(data_string, format))
if len(data_string) != found.end():
rest = data_string[found.end():]
# Specific check for '%:z' directive
if (
"colon_z" in found.re.groupindex
and found.group("colon_z") is not None
and rest[0] != ":"
):
raise ValueError(
f"Missing colon in %:z before '{rest}', got '{data_string}'"
)
raise ValueError("unconverted data remains: %s" % rest)
iso_year = year = None
month = day = 1
hour = minute = second = fraction = 0
tz = -1
gmtoff = None
gmtoff_fraction = 0
iso_week = week_of_year = None
week_of_year_start = None
# weekday and julian defaulted to None so as to signal need to calculate
# values
weekday = julian = None
found_dict = found.groupdict()
if locale_time.LC_alt_digits:
def parse_int(s):
try:
return locale_time.LC_alt_digits.index(s)
except ValueError:View on GitHub (pinned to bc6749cc3b)
Solutions
- Add directives for the remaining text (%H:%M:%S, %f, %Z, %z) or matching literals
- Strip/slice the input to exactly what the format covers: data.split(' ')[0]
- Use dateutil.parser or fromisoformat for variable-length inputs
Example fix
# before
>>> datetime.strptime('2020-01-01 12:00', '%Y-%m-%d')
ValueError: unconverted data remains: 12:00
# after
>>> datetime.strptime('2020-01-01 12:00', '%Y-%m-%d %H:%M')
datetime.datetime(2020, 1, 1, 12, 0) Defensive patterns
Strategy: fallback
Validate before calling
from datetime import datetime
def parse_prefix(s: str, fmt: str):
for end in range(len(s), 0, -1):
try:
return datetime.strptime(s[:end], fmt)
except ValueError:
continue
raise ValueError(f'no prefix of {s!r} matches {fmt!r}') Try / catch
try:
dt = datetime.strptime(line.strip(), fmt)
except ValueError as e:
if str(e).startswith('unconverted data remains'):
dt = datetime.strptime(line.strip()[:len_covered(fmt)], fmt)
else:
raise Prevention
- Cover every field of the input in the format (times, fraction, zone)
- Strip trailing newlines/whitespace from file-read lines before parsing
- Log the reported 'rest' substring — it tells you exactly which directive is missing
When it happens
Trigger: datetime.strptime('2020-01-01 12:00', '%Y-%m-%d') — the time part ' 12:00' remains; or a trailing timezone name, milliseconds, or newline not covered by the format.
Common situations: Log lines with extra trailing fields; input with trailing '\n' from file.readline(); forgetting %H:%M:%S or %f/%Z directives for the tail of the string.
Related errors
- time data %r does not match format %r
- Day of month directive '%d' may not be used without a year d
- Inconsistent use of : in {found_dict[group_key]}
- Day of the year directive '%j' is not compatible with ISO ye
- ISO year directive '%G' must be used with the ISO week direc
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/e9b6fd1b6482216f.
Report an issue: GitHub.