Skip to content

fix: replaced deprecated datetime.utc() with datetime.now(timezone.utc)#2075

Merged
Vchen7629 merged 7 commits into
mainfrom
deprecated-datetime-utcnow-fix
Jul 13, 2026
Merged

fix: replaced deprecated datetime.utc() with datetime.now(timezone.utc)#2075
Vchen7629 merged 7 commits into
mainfrom
deprecated-datetime-utcnow-fix

Conversation

@Vchen7629

@Vchen7629 Vchen7629 commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fixes #1552 . Replaces all 33 deprecated datetime.utcnow() calls with timezone-aware datetime.now(timezone.utc) across the codebase, fixing a AttributeError at runtime since utcnow() was removed in Python 3.13 which is used in the backend base image.

Changes

  • ORM models (api_key, user, role, conversation, workspace_config, audit_log, user_role, migration_status, session_ownership): replaced default_factory=datetime.utcnow with default_factory=lambda: datetime.now(timezone.utc)
  • Repositories (api_key_repo, conversation_repo, workspace_config_repo): replaced direct datetime.utcnow() calls
  • Services (api_key_service, auth_service, knowledge_filter_service, session_ownership_service): replaced direct calls and .isoformat() usages
  • Connectors (onedrive, sharepoint): replaced expiry timestamp calculations
  • API handlers (knowledge_filter, settings/helpers): replaced dict timestamp values
  • Other (session_manager, migrations_runtime, alembic/0002_seed_roles_permissions): replaced remaining call sites
  • Added timezone to from datetime import ... in each affected file

Summary by CodeRabbit

  • Bug Fixes
    • Standardized all created/updated/activity timestamps to timezone-aware UTC, improving consistency across authentication flows, session ownership, subscriptions, knowledge filters, audit records, API keys, and migration tracking.
    • Updated token and external connector subscription expiration calculations to use the same UTC basis, reducing time-zone interpretation issues.
  • Refactor
    • Modernized nullable typing and timestamp default generation to be consistent across the codebase while keeping the same external behavior and outputs.

Signed-off-by: vchen7629 <chenvincent7629@gmail.com>
@github-actions github-actions Bot added backend 🔷 Issues related to backend services (OpenSearch, Langflow, APIs) bug 🔴 Something isn't working. labels Jul 10, 2026
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2b6a1b3b-3c9a-489e-a6a4-7203c61acae4

📥 Commits

Reviewing files that changed from the base of the PR and between d9599c4 and cbdf653.

📒 Files selected for processing (1)
  • src/db/migrations_runtime.py

Walkthrough

The changes replace datetime.utcnow() with timezone-aware UTC timestamps across migrations, APIs, models, repositories, connectors, and services. Legacy persisted datetimes are normalized to UTC, and related nullable type annotations use modern union syntax.

Changes

Timezone-aware timestamp migration

Layer / File(s) Summary
Entry points and external integrations
alembic/versions/0002_seed_roles_permissions.py, src/api/..., src/connectors/...
Seeded role timestamps, API payload timestamps, webhook timestamps, settings-helper timestamps, and connector subscription expiries now use explicit UTC values.
Model timestamp defaults
src/db/models/...
Model timestamp defaults now use datetime.now(UTC), while nullable annotations use modern union syntax.
Database runtime and repositories
src/db/migrations_runtime.py, src/db/repositories/...
Migration completion and legacy datetime parsing now normalize values to UTC; repository timestamp writes and annotations are updated accordingly.
Services and session claims
src/services/..., src/session_manager.py
Service documents, OAuth expiry, session ownership records, subscription removals, and JWT claims now use timezone-aware UTC timestamps; related typing is modernized.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Suggested reviewers: mfortman11, mpawlow, zzzming

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning PEP 604 typing modernizations and formatting-only edits are unrelated to the utcnow fix and appear out of scope for #1552. Split the typing and formatting cleanup into a separate PR and keep this one focused on timezone-aware datetime replacements and parsing fixes.
Docstring Coverage ⚠️ Warning Docstring coverage is 12.90% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: replacing deprecated UTC datetime calls with timezone-aware now(timezone.utc).
Linked Issues check ✅ Passed The changes satisfy #1552 by replacing utcnow calls with UTC-aware now() usage and adding legacy datetime normalization where needed.
📋 Issue Planner

Built with CodeRabbit's Coding Plans for faster development and fewer bugs.

View plan used: #1552

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch deprecated-datetime-utcnow-fix

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added bug 🔴 Something isn't working. and removed bug 🔴 Something isn't working. labels Jul 10, 2026
@github-actions github-actions Bot added bug 🔴 Something isn't working. and removed bug 🔴 Something isn't working. labels Jul 10, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (2)
src/services/knowledge_filter_service.py (1)

354-359: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove unused timezone from local import.

The local import from datetime import datetime, timezone on line 354 imports timezone, but it is never used — UTC comes from the module-level import on line 1. This is a newly introduced unused import.

♻️ Proposed fix
-            from datetime import datetime, timezone
+            from datetime import datetime
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/services/knowledge_filter_service.py` around lines 354 - 359, Remove the
unused timezone symbol from the local datetime import in the update body logic,
retaining only datetime; continue using the module-level UTC referenced by the
relevant subscription update method.
src/db/repositories/api_key_repo.py (1)

36-41: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consolidate the inline datetime import to the top level.

UTC is already imported at the top level (line 7), and datetime is only needed in revoke. Moving datetime to the top-level import eliminates the inline import and the unused timezone it pulls in.

♻️ Proposed refactor
 from datetime import UTC
+from datetime import UTC, datetime
     async def revoke(self, key_id: str) -> None:
-        from datetime import datetime, timezone
-
         row = await self.session.get(ApiKey, key_id)
         if row:
             row.revoked = True
             row.revoked_at = datetime.now(UTC)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/db/repositories/api_key_repo.py` around lines 36 - 41, Move the datetime
import to the module-level imports in the API key repository, retaining only
datetime and removing the inline import of datetime and timezone from revoke.
Keep revoke using datetime.now(UTC) when setting revoked_at.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@alembic/versions/0002_seed_roles_permissions.py`:
- Around line 15-16: Remove the unused timezone and Union imports from the
module’s import section, retaining only the datetime symbols referenced by the
seed logic so Ruff no longer reports F401.

In `@src/api/knowledge_filter.py`:
- Line 3: Remove the unused timezone symbol from the datetime import in the
knowledge filter module, keeping only the imports required by datetime.now(UTC).

In `@src/api/settings/helpers.py`:
- Line 165: Remove the unused timezone symbol from the datetime import in the
settings helper module, leaving only the imported datetime symbol while
retaining use of the module-level UTC constant.

In `@src/connectors/onedrive/connector.py`:
- Line 407: Remove the unused timezone symbol from the datetime import in the
affected module, retaining only the imports used by the connector, including
UTC.

In `@src/connectors/sharepoint/connector.py`:
- Line 442: Remove the unused timezone symbol from the datetime import in the
SharePoint connector, keeping only the datetime components used by the relevant
method, including UTC.

In `@src/db/models/audit_log.py`:
- Line 1: Remove the unused timezone symbol from the datetime import in the
audit log module, keeping only the datetime symbols actually referenced,
including UTC.
- Around line 12-24: Update the timestamp field `ts` in the audit log model and
all other timestamp model fields introduced in this PR to use timezone-aware
database columns by configuring their SQLAlchemy `DateTime` type with
`timezone=True`, while retaining the UTC-aware default factory such as
`datetime.now(UTC)`.

---

Nitpick comments:
In `@src/db/repositories/api_key_repo.py`:
- Around line 36-41: Move the datetime import to the module-level imports in the
API key repository, retaining only datetime and removing the inline import of
datetime and timezone from revoke. Keep revoke using datetime.now(UTC) when
setting revoked_at.

In `@src/services/knowledge_filter_service.py`:
- Around line 354-359: Remove the unused timezone symbol from the local datetime
import in the update body logic, retaining only datetime; continue using the
module-level UTC referenced by the relevant subscription update method.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 34e5d5a2-c870-4837-baba-f5fed2b49f16

📥 Commits

Reviewing files that changed from the base of the PR and between 9b536d0 and 4fde14f.

📒 Files selected for processing (23)
  • alembic/versions/0002_seed_roles_permissions.py
  • src/api/knowledge_filter.py
  • src/api/settings/helpers.py
  • src/connectors/onedrive/connector.py
  • src/connectors/sharepoint/connector.py
  • src/db/migrations_runtime.py
  • src/db/models/api_key.py
  • src/db/models/audit_log.py
  • src/db/models/conversation.py
  • src/db/models/migration_status.py
  • src/db/models/role.py
  • src/db/models/session_ownership.py
  • src/db/models/user.py
  • src/db/models/user_role.py
  • src/db/models/workspace_config.py
  • src/db/repositories/api_key_repo.py
  • src/db/repositories/conversation_repo.py
  • src/db/repositories/workspace_config_repo.py
  • src/services/api_key_service.py
  • src/services/auth_service.py
  • src/services/knowledge_filter_service.py
  • src/services/session_ownership_service.py
  • src/session_manager.py

Comment thread alembic/versions/0002_seed_roles_permissions.py Outdated
Comment thread src/api/knowledge_filter.py Outdated
Comment thread src/api/settings/helpers.py Outdated
Comment thread src/connectors/onedrive/connector.py Outdated
Comment thread src/connectors/sharepoint/connector.py Outdated
Comment thread src/db/models/audit_log.py Outdated
Comment on lines +12 to +24
ts: datetime = Field(default_factory=lambda: datetime.now(UTC), index=True)
actor_user_id: str | None = Field(
default=None, foreign_key="users.id", max_length=64, index=True
)
actor_api_key_id: Optional[str] = Field(default=None, max_length=64)
actor_api_key_id: str | None = Field(default=None, max_length=64)
event: str = Field(max_length=128, index=True)
target_type: Optional[str] = Field(default=None, max_length=64)
target_id: Optional[str] = Field(default=None, max_length=128)
audit_metadata: Optional[dict] = Field(
target_type: str | None = Field(default=None, max_length=64)
target_id: str | None = Field(default=None, max_length=128)
audit_metadata: dict | None = Field(
default=None, sa_column=Column("metadata", JSON, nullable=True)
)
ip: Optional[str] = Field(default=None, max_length=64)
user_agent: Optional[str] = Field(default=None, max_length=512)
ip: str | None = Field(default=None, max_length=64)
user_agent: str | None = Field(default=None, max_length=512)

@coderabbitai coderabbitai Bot Jul 10, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check for timezone=True in model definitions
rg -n 'timezone.*True' src/db/models/ --type=py

# Check for custom SQLAlchemy DateTime types
rg -n 'class.*DateTime' src/db/ --type=py

# Check for database URL configuration
rg -n 'DATABASE_URL|database_url|db_url' src/config/ --type=py

# Check if timezone is used beyond imports in all changed files
for f in src/db/models/audit_log.py src/db/models/conversation.py src/db/models/role.py src/db/models/workspace_config.py src/db/repositories/api_key_repo.py src/db/repositories/conversation_repo.py src/db/repositories/workspace_config_repo.py; do
  echo "=== $f ==="
  rg -n 'timezone' "$f" | rg -v 'from datetime import'
done

Repository: langflow-ai/openrag

Length of output: 448


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- audit_log.py outline ---'
ast-grep outline src/db/models/audit_log.py --view expanded || true

echo '--- audit_log.py lines ---'
nl -ba src/db/models/audit_log.py | sed -n '1,220p'

echo '--- other model files with timestamp fields ---'
for f in src/db/models/conversation.py src/db/models/role.py src/db/models/workspace_config.py; do
  echo "=== $f ==="
  nl -ba "$f" | sed -n '1,220p'
done

echo '--- search for DateTime/Timezone column declarations ---'
rg -n 'DateTime|timezone\s*=' src -g '*.py' || true

echo '--- search for engine/backend config ---'
rg -n 'create_engine|sqlite|postgres|postgresql|mysql|DATABASE_URL|database_url|db_url|engine' src -g '*.py' || true

Repository: langflow-ai/openrag

Length of output: 960


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- audit_log.py ---'
sed -n '1,220p' src/db/models/audit_log.py

echo '--- conversation.py ---'
sed -n '1,220p' src/db/models/conversation.py

echo '--- role.py ---'
sed -n '1,220p' src/db/models/role.py

echo '--- workspace_config.py ---'
sed -n '1,260p' src/db/models/workspace_config.py

echo '--- explicit DateTime/timezone usage in src ---'
rg -n 'DateTime|timezone\s*=' src -g '*.py' || true

echo '--- DB/backend config mentions ---'
rg -n 'DATABASE_URL|database_url|db_url|sqlite|postgresql|postgres|mysql|create_engine|engine' src -g '*.py' || true

Repository: langflow-ai/openrag

Length of output: 12999


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- timestamp field usages ---'
rg -n '\b(ts|created_at|last_activity|updated_at)\b' src -g '*.py' || true

echo '--- datetime comparisons / UTC now usage ---'
rg -n 'datetime\.now\(UTC\)|UTC\)|<|>|<=|>=|replace\(tzinfo|astimezone|timezone' src/db src/services src/app -g '*.py' || true

echo '--- db engine file ---'
sed -n '1,220p' src/db/engine.py

Repository: langflow-ai/openrag

Length of output: 50375


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- timestamp field usages ---'
rg -n '\b(ts|created_at|last_activity|updated_at)\b' src -g '*.py' || true

echo '--- datetime comparisons / UTC now usage ---'
rg -n 'datetime\.now\(UTC\)|astimezone|replace\(tzinfo|timezone' src/db src/services src/app -g '*.py' || true

echo '--- db engine file ---'
sed -n '1,220p' src/db/engine.py

Repository: langflow-ai/openrag

Length of output: 20789


Use timezone-aware columns for the UTC timestamp fields
In src/db/models/audit_log.py and the other timestamp models in this PR, datetime.now(UTC) still maps to the default naive DateTime. Add timezone=True on those DB-backed timestamp columns so rows round-trip with tzinfo intact and don’t diverge on serialization or comparisons.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/db/models/audit_log.py` around lines 12 - 24, Update the timestamp field
`ts` in the audit log model and all other timestamp model fields introduced in
this PR to use timezone-aware database columns by configuring their SQLAlchemy
`DateTime` type with `timezone=True`, while retaining the UTC-aware default
factory such as `datetime.now(UTC)`.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be out of scope for this PR

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Vchen7629, that's fair — adding timezone=True to all the DB-backed timestamp columns is a broader change than what this PR set out to do (which is fixing the datetime.utcnow() removal in Python 3.13). I'll leave it as-is here.

Would you like me to open a follow-up issue to track adding timezone=True to the timestamp columns, so it doesn't get lost?

Signed-off-by: vchen7629 <chenvincent7629@gmail.com>
Signed-off-by: vchen7629 <chenvincent7629@gmail.com>
@github-actions github-actions Bot added bug 🔴 Something isn't working. and removed bug 🔴 Something isn't working. labels Jul 10, 2026
@edwinjosechittilappilly

Copy link
Copy Markdown
Collaborator

@coderabbitai

review suggestion.
Guard against naive/aware timestamp mixing in the JSON→DB migration

File: src/db/migrations_runtime.py

Legacy JSON files may contain naive ISO strings (written by the old datetime.utcnow().isoformat() code before this fix shipped). Parsing them with fromisoformat() and mixing with new aware rows risks a TypeError if anything later compares them. Normalize on parse:

def _parse_legacy_dt(value: str | None) -> datetime | None:
if not value:
return None
try:
dt = datetime.fromisoformat(value)
except Exception: # noqa: BLE001
return None
return dt if dt.tzinfo is not None else dt.replace(tzinfo=UTC)

Then use _parse_legacy_dt(data.get("created_at")) etc. in place of the current inline try/except blocks (lines ~215–262). This makes every value entering the DB tz-aware regardless of when the source JSON was written, closing off the mismatch at the one place legacy data is ingested.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd migrations_runtime.py
sed -n '190,270p' src/db/migrations_runtime.py

Length of output: 3392


@edwinjosechittilappilly Good catch — this is a real gap. The four inline try/except datetime.fromisoformat(...) blocks in migrate_chat_history_json_to_db (session created_at/last_accessed, and conversation created_at/last_activity) will happily return naive datetimes if the legacy JSON was written by the old datetime.utcnow().isoformat() code, while everything else in this PR is now tz-aware. That's exactly the kind of latent TypeError: can't compare/subtract naive and aware datetimes bug that only surfaces later (e.g., in ordering, last_activity comparisons, or once these rows meet aware ones from new code paths).

Your _parse_legacy_dt helper is the right fix — normalize once at the ingestion boundary rather than patching every consumer downstream. Suggested implementation:

def _parse_legacy_dt(value: str | None) -> datetime | None:
    """Parse a legacy ISO datetime string, coercing naive values to UTC."""
    if not value:
        return None
    try:
        dt = datetime.fromisoformat(value)
    except (TypeError, ValueError):
        return None
    return dt if dt.tzinfo is not None else dt.replace(tzinfo=UTC)

And then replace the four blocks, e.g.:

created = _parse_legacy_dt(data.get("created_at"))
last = _parse_legacy_dt(data.get("last_accessed"))
...
created = _parse_legacy_dt(meta.get("created_at"))
last = _parse_legacy_dt(meta.get("last_activity"))

One small tweak: I'd narrow the caught exception to (TypeError, ValueError) instead of a broad Exception, since fromisoformat only raises those for malformed input — keeps the noqa: BLE001 unnecessary and avoids silently swallowing unrelated bugs.

I'll flag this as a follow-up suggestion on the PR.


✏️ Learnings added
Learnt from: edwinjosechittilappilly
URL: https://github.com/langflow-ai/openrag/pull/2075

Timestamp: 2026-07-10T22:17:46.141Z
Learning: In src/db/migrations_runtime.py, when parsing legacy JSON-sourced ISO datetime strings (e.g., in migrate_chat_history_json_to_db for session_ownership.json and conversations.json), naive datetimes must be normalized to UTC-aware datetimes (e.g., via `dt.replace(tzinfo=UTC)` when `dt.tzinfo is None`) before use, since legacy JSON files may have been written using the old `datetime.utcnow().isoformat()` format and the rest of the codebase now uses timezone-aware `datetime.now(UTC)`. Mixing naive and aware datetimes risks TypeError on comparison.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@github-actions github-actions Bot added bug 🔴 Something isn't working. and removed bug 🔴 Something isn't working. labels Jul 10, 2026
@github-actions github-actions Bot added bug 🔴 Something isn't working. and removed bug 🔴 Something isn't working. labels Jul 10, 2026

@edwinjosechittilappilly edwinjosechittilappilly left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@github-actions github-actions Bot added the lgtm label Jul 13, 2026
@Vchen7629
Vchen7629 merged commit aeb0559 into main Jul 13, 2026
36 of 40 checks passed
@github-actions
github-actions Bot deleted the deprecated-datetime-utcnow-fix branch July 13, 2026 15:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend 🔷 Issues related to backend services (OpenSearch, Langflow, APIs) bug 🔴 Something isn't working. lgtm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Replace deprecated datetime.utcnow() with timezone-aware datetime.now(timezone.utc) throughout the codebase

2 participants