apache/beam · error · ValueError
Could not parse RFC 3339 string
Error message
Could not parse RFC 3339 string '{}' due to error: '{}'. What it means
from_rfc3339() parses the string with dateutil.parser.isoparse(); if that raises ValueError, it is re-raised with a message including both the input string and the underlying parse error. This means the input was not a valid RFC 3339 / ISO-8601 timestamp.
Solutions
- Validate/fix the input to RFC 3339 form, e.g. '2024-01-01T00:00:00Z'
- Read the wrapped inner error (the trailing 'error' in the message) to pinpoint the malformed part
- Pre-parse with dateutil.parser.parse for lenient formats, then convert to an aware UTC datetime and use Timestamp.of
Example fix
// before ts = Timestamp.from_rfc3339(user_input) # '01/02/2024 3pm' // after dt = dateutil.parser.parse(user_input) ts = Timestamp.of(dt.astimezone(pytz.utc))
Defensive patterns
Strategy: try-catch
Validate before calling
RFC3339_RE = re.compile(r'^\d{4}-\d{2}-\d{2}[Tt ]\d{2}:\d{2}:\d{2}(\.\d+)?([Zz]|[+-]\d{2}:?\d{2})$')
if not RFC3339_RE.match(s):
raise ValueError(f'not RFC 3339: {s!r}') Try / catch
try:
ts = Timestamp.from_rfc3339(s)
except ValueError as e:
log.error('bad timestamp %r: %s', s, e)
ts = None # or dead-letter the record Prevention
- Validate input format before parsing; surface the inner error message
- Fix upstream producers to emit RFC 3339 with an explicit offset
- Keep a dead-letter path for unparseable timestamps in pipelines
When it happens
Trigger: Timestamp.from_rfc3339('2024-13-45T99:00:00Z'); 'Jan 1 2024'; empty string; truncated strings like '2024-01-01T10:'; timezone-less strings that isoparse rejects in strict contexts.
Common situations: Free-form user input into an API field; log-parsing pipelines fed non-RFC3339 formats; typos like double T or missing seconds parts; locale-formatted dates.
Related errors
- Could not parse RFC 3339 string
- micros and subseconds are mutually exclusive, got micros=
- micros implies microsecond precision (6) but precision was
- No timestamp in this context.
- Timestamp precision must be between 0 and
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/75f7905565f98e77.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/python/apache_beam/utils/timestamp.py:191
@classmethod
def from_rfc3339(cls, rfc3339: str) -> 'Timestamp':
"""Create a ``Timestamp`` instance from an RFC 3339 compliant string.
Fractional seconds up to microseconds produce a microsecond-precision
Timestamp; a longer fraction (up to nanoseconds) produces a Timestamp
whose precision matches the number of fractional digits.
.. note::
All timezones are implicitly converted to UTC.
Args:
rfc3339: String in RFC 3339 form.
"""
try:
dt = dateutil.parser.isoparse(rfc3339).astimezone(pytz.UTC)
except ValueError as e:
raise ValueError(
"Could not parse RFC 3339 string '{}' due to error: '{}'.".format(
rfc3339, e))
timestamp = cls.from_utc_datetime(dt)
# dateutil silently truncates fractional seconds to microseconds; parse
# any sub-microsecond digits ourselves to avoid losing precision.
fraction = re.search(r'[0-9]{2}[.,]([0-9]{7,})', rfc3339)
if fraction:
digits = fraction.group(1)
if len(digits) > cls.NANOS_PRECISION:
raise ValueError(
"Could not parse RFC 3339 string '%s': fractional seconds "
'beyond nanosecond precision are not supported.' % rfc3339)
precision = len(digits)
sub_micro = int(digits[cls.MICROS_PRECISION:])
return Timestamp(
timestamp.seconds(),
timestamp.subseconds() * _POW_10[precision - cls.MICROS_PRECISION] +
sub_micro,View on GitHub (pinned to 12126d8942)