apache/beam · error · ValueError
dt not in UTC
Error message
dt not in UTC: %s
What it means
from_utc_datetime() accepts only datetimes whose tzinfo is exactly pytz.utc or datetime.timezone.utc; aware datetimes in other timezones (e.g. pytz timezone 'US/Pacific' or a +05:00 fixed offset) raise this ValueError. The API name means 'from a UTC datetime', not 'convert any datetime to UTC'.
Solutions
- Convert first: dt.astimezone(pytz.utc) or dt.astimezone(datetime.timezone.utc), then call from_utc_datetime
- Use Timestamp.of(dt), which handles any aware datetime via from_utc_datetime after conversion in newer code paths
- Store/produce UTC datetimes at the source instead of local ones
Example fix
// before Timestamp.from_utc_datetime(local_dt) // after Timestamp.from_utc_datetime(local_dt.astimezone(pytz.utc))
Defensive patterns
Strategy: type-guard
Validate before calling
if dt.tzinfo not in (pytz.utc, datetime.timezone.utc):
dt = dt.astimezone(pytz.utc) Type guard
def is_utc(dt: datetime.datetime) -> bool:
return dt.tzinfo in (pytz.utc, datetime.timezone.utc) Try / catch
try:
ts = Timestamp.from_utc_datetime(dt)
except ValueError as e:
if 'not in UTC' in str(e):
ts = Timestamp.from_utc_datetime(dt.astimezone(pytz.utc))
else:
raise Prevention
- Normalize all datetimes to UTC at system boundaries with astimezone(pytz.utc)
- Only pass UTC datetimes to from_utc_datetime; use Timestamp.of for mixed tz
- Beware pytz.localize with non-UTC zones produces non-UTC tzinfo
When it happens
Trigger: Passing datetime(2024,1,1, tzinfo=timezone(timedelta(hours=5))); passing pytz.timezone('UTC').localize(dt) variants whose tzinfo compares unequal to pytz.utc; passing dt.astimezone() results in some non-UTC tz.
Common situations: Application timezone-aware datetimes passed directly instead of converted; pytz's localize used with wrong tz; reading aware datetimes from databases in local tz.
Related errors
- dt has no timezone info…
- All PCollections must belong to the same pipeline.
- cache_root GCS bucket path is invalid.
- Converting %r to datetime truncates it to microseconds. Set…
- Could not parse RFC 3339 string
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/b4bdaa1c50c09925.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/python/apache_beam/utils/timestamp.py:167
@staticmethod
def _epoch_datetime_utc() -> datetime.datetime:
return datetime.datetime.fromtimestamp(0, pytz.utc)
@classmethod
def from_utc_datetime(cls, dt: datetime.datetime) -> 'Timestamp':
"""Create a ``Timestamp`` instance from a ``datetime.datetime`` object.
Args:
dt: A ``datetime.datetime`` object in UTC (offset-aware).
"""
if dt.tzinfo is None:
raise ValueError(
"dt has no timezone info " +
"(https://docs.python.org/3/library/datetime.html" +
"#aware-and-naive-objects): %s" % dt)
if dt.tzinfo != pytz.utc and dt.tzinfo != datetime.timezone.utc:
raise ValueError('dt not in UTC: %s' % dt)
duration = dt - cls._epoch_datetime_utc()
# Avoid total_seconds(): its float result can be off by a microsecond.
return Timestamp(
seconds=duration.days * 86400 + duration.seconds,
micros=duration.microseconds)
@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:View on GitHub (pinned to 12126d8942)