Skip to content

Migration unpickler blocks builtins.getattr on py311 + crewai extras, silently dropping v0 EventActions during migration #6636

Description

@loponly

** Please make sure you read the contribution guide and file the issues in the right place. **

Describe the bug

The v0→v1 session migration tool's restricted unpickler (added in 9db48ce9, "fix(migration): restrict unpickling of v0 actions blobs") blocks builtins.getattr, and on Python 3.11 — specifically an environment with the full test extras installed, where crewai[tools] applies per the pyproject marker python_version>='3.11' and python_version<'3.12' — the pickled EventActions graph contains a getattr global. The unpickler rejects it, _safe_unpickle_actions logs a WARNING and falls back to empty actions, and migrated events silently lose requested_auth_configs and compaction.

Observable today as a deterministic unit-test failure on the py311 tox environment:

FAILED tests/unittests/sessions/migration/test_migration.py::test_migrate_from_sqlalchemy_pickle_preserves_nested_safe_actions_pickle
AssertionError: assert 'fc-auth' in {}

with this in the captured log:

WARNING ... Failed to unpickle actions for event event1: Blocked global during migration unpickle: builtins.getattr

To Reproduce

Steps to reproduce (repo at current main):

  1. uv venv --python "python3.11" .venv && source .venv/bin/activate && uv sync --all-extras
  2. pytest "tests/unittests/sessions/migration/test_migration.py::test_migrate_from_sqlalchemy_pickle_preserves_nested_safe_actions_pickle"
  3. Test fails as above. The same test passes on py310, py312, py313, and py314 tox environments (tox run: py310 OK, py311 FAIL, py312 OK, py313 OK, py314 OK).

Ruling out version skew: pydantic (2.12.5), fastapi (0.141.1), and google-genai (2.17.0) are identical across the py310/py311/py312 environments — the only material difference in the failing environment is the presence of crewai and its transitive dependencies, which only install on 3.11. A plausible mechanism is a pydantic plugin registered via entry points by one of those transitive dependencies altering how pydantic model instances pickle (introducing a getattr reduction), but I have not bisected the exact package.

Expected behavior

Either the migration unpickler accepts the pickle streams that pydantic models actually produce in every supported environment (so nested EventActions content survives migration), or — if builtins.getattr must stay blocked for hardening reasons — the migration should not silently degrade to {} for blobs a supported environment wrote. Silent data loss during migration is the worst outcome of the current behavior; the test correctly catches it.

Desktop:

  • OS: macOS (Darwin 24.6.0)
  • Python version: 3.11 (failing); 3.10/3.12/3.13/3.14 (passing)
  • ADK version: current main (c5672030)

Additional context

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions