Skip to content

Runner._compute_artifact_delta_for_rewind saves artifacts with "file_data", which GcsArtifactService and FileArtifactService don't supportΒ #4932

Closed

Description

@lucasbarzotto-axonify

πŸ”΄ Required Information

Describe the Bug:

Runner._compute_artifact_delta_for_rewind (runners.py:755–765) restores historical artifact versions by constructing a types.Part(file_data=types.FileData(file_uri=...)) and passing it to artifact_service.save_artifact. However, GcsArtifactService._save_artifact explicitly raises NotImplementedError when it receives a file_data part (gcs_artifact_service.py:232–236), and FileArtifactService has no file_data handling path at all.

This means rewind_async crashes at runtime for any application using GcsArtifactService or FileArtifactService when the session contains artifacts that changed after the rewind point. Only InMemoryArtifactService works, since it stores the Part object as-is without attempting to extract bytes.

Steps to Reproduce:

  1. Create an ADK application using GcsArtifactService (or FileArtifactService)
  2. Run agent invocations that produce artifacts (e.g. save an image via tool_context.save_artifact)
  3. Run additional invocations that modify or create new versions of the same artifact
  4. Call runner.rewind_async(user_id=..., session_id=..., rewind_before_invocation_id="<invocation_before_artifact_change>")
  5. Observe NotImplementedError from GcsArtifactService
NotImplementedError: Saving artifact with file_data is not supported yet in GcsArtifactService.

Expected Behavior:

rewind_async should successfully restore artifacts to their historical version regardless of which ArtifactService implementation is used. Since load_artifact already returns artifact content as inline_data (it reads the actual bytes from storage), the rewind code should use load_artifact to read the historical version and then save_artifact with inline_data β€” which all artifact service implementations support.

Observed Behavior:

rewind_async raises NotImplementedError when any artifact needs restoration and the artifact service is GcsArtifactService:

NotImplementedError: Saving artifact with file_data is not supported yet in GcsArtifactService.

The crash occurs at runners.py:766 when calling self.artifact_service.save_artifact(... artifact=artifact ...) with the file_data part constructed at line 765.

Root Cause:

In runners.py:755–765, _compute_artifact_delta_for_rewind constructs an internal artifact:// URI and wraps it in file_data:

artifact_uri = artifact_util.get_artifact_uri(
    app_name=self.app_name,
    user_id=session.user_id,
    session_id=session.id,
    filename=filename,
    version=vt,
)
artifact = types.Part(file_data=types.FileData(file_uri=artifact_uri))
await self.artifact_service.save_artifact(
    app_name=self.app_name,
    user_id=session.user_id,
    session_id=session.id,
    filename=filename,
    artifact=artifact,
)

But GcsArtifactService._save_artifact (gcs_artifact_service.py:232–236) rejects file_data:

elif artifact.file_data:
    raise NotImplementedError(
        "Saving artifact with file_data is not supported yet in"
        " GcsArtifactService."
    )

And FileArtifactService._save_artifact only handles inline_data and text β€” a file_data part falls through to the "Artifact must have either inline_data or text" validation error.

Suggested Fix:

Instead of constructing a file_data reference, the rewind code should load_artifact at the target version (which returns the actual bytes as inline_data) and then save_artifact with that inline_data part. This works with all artifact service implementations:

# Instead of constructing a file_data reference:
loaded = await self.artifact_service.load_artifact(
    app_name=self.app_name,
    user_id=session.user_id,
    session_id=session.id,
    filename=filename,
    version=vt,
)
if loaded and loaded.inline_data:
    artifact = types.Part(
        inline_data=types.Blob(
            mime_type=loaded.inline_data.mime_type,
            data=loaded.inline_data.data,
        )
    )
else:
    # Fallback: artifact couldn't be loaded, mark as empty
    artifact = types.Part(
        inline_data=types.Blob(mime_type="application/octet-stream", data=b"")
    )

Note: the code already uses inline_data for the "artifact did not exist at rewind point" case (runners.py:750–753) β€” the fix just extends this approach to the "restore existing version" case.

Environment Details:

  • ADK Library Version: 1.27.1
  • Desktop OS: macOS (darwin 24.6.0)
  • Python Version: 3.13

Model Information:

  • Are you using LiteLLM: No
  • Which model is being used: gemini-2.5-pro

🟑 Optional Information

How often has this issue occurred?:

  • Always (100%) β€” occurs whenever rewind_async needs to restore an artifact and the artifact service is GcsArtifactService or FileArtifactService

Activity

  1. added
    services[Component] This issue is related to runtime services, e.g. sessions, memory, artifacts, etc
    on Mar 20, 2026
  2. added theissue type on Mar 20, 2026
  3. surajksharma07 commented on Mar 24, 2026

    @surajksharma07
    Collaborator

    @lucasbarzotto-axonify The issue is that _compute_artifact_delta_for_rewind builds a file_data URI reference and passes it directly to save_artifact, but neither FileArtifactService nor GcsArtifactService have any handler for that format β€” so it falls over before it can do anything useful.

    A workaround worth trying: load the artifact at the target version via load_artifact(version=vt) and re-save using its inline_data instead.
    That path works consistently across all artifact service implementations, so it should hold up regardless of which backend you're running.

    Could you verify whether that clears the crash on your end before we finalize PR #4979?

    Team is looking more into it.

  4. lucasbarzotto-axonify commented on Mar 24, 2026

    @lucasbarzotto-axonify
    Author

    Hi @surajksharma07, thanks for confirming the issue.

    Yes, I've run a local test and confirmed that this change fixes the problem. I've also added a couple of minor comments on the PR.

    Thanks!

  5. surajksharma07 commented on Mar 25, 2026

    @surajksharma07
    Collaborator

    @lucasbarzotto-axonify Thanks for verifying the fix and for the review comments on PR #4979 β€” really appreciate the thorough testing.

    The team will take a look at your comments on the PR and get it finalized.

  6. surajksharma07 commented on Mar 25, 2026

    @surajksharma07
    Collaborator

    @DeanChensj Please have a look inton it once.

  7. removed their assignment
    on Apr 15, 2026
  8. self-assigned this
    on Apr 24, 2026
  9. added a commit that references this issue on Apr 24, 2026
    c3d50db
  10. added a commit that references this issue on Aug 11, 2026
    60151fb
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

needs review[Status] The PR/issue is awaiting review from the maintainerservices[Component] This issue is related to runtime services, e.g. sessions, memory, artifacts, etc

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions