Skip to content

[BUG] S3SessionManager with empty prefix produces leading slash in S3 keys causing session restore failure on MinIO and S3-compatible backends #1863

@AadarshBhalerao

Description

@AadarshBhalerao

Checks

  • I have updated to the lastest minor and patch version of Strands
  • I have checked the documentation and this is not expected behavior
  • I have searched ./issues and there are no duplicates of my issue

Strands Version

1.22.0, 1.30.0

Python Version

3.12.3

Operating System

Linux (WSL2, Ubuntu)

Installation Method

pip

Steps to Reproduce

  1. Create an S3SessionManager with default prefix="" (no prefix argument)
  2. Create an Agent with the session manager and send a message
  3. Stop the process
  4. Create a new S3SessionManager with the same session_id
  5. Create a new Agent with the new session manager
  6. Observe that agent.messages is empty — session was not restored

Expected Behavior

When an Agent is recreated with the same session_id, all previous messages
are restored from S3 and agent.messages contains the full conversation history.

Actual Behavior

agent.messages is always empty on restore. The agent starts fresh every time,
overwriting existing messages from index 0.

Additional Context

Root cause: get_session_path with empty prefix (default) produces keys with
a leading slash e.g. /session
/agents/agent_default/agent.json

MinIO and some S3-compatible backends strip the leading slash on write,
storing the key as session_/... but the read uses /session_/...
which never matches. read_agent() returns None, initialize() takes the
new-session branch and starts from scratch.

Verified by writing a key with leading slash to MinIO and listing with
both /prefix and prefix, only the one without leading slash finds the object.

Possible Solution

def _get_session_path(self, session_id: str) -> str:
    """
	Get session S3 prefix.

    Args:
        session_id: ID for the session.

    Raises:
        ValueError: If session id contains a path separator.
    """
    session_id = _identifier.validate(session_id, _identifier.Identifier.SESSION)

    if self.prefix:
		return f"{self.prefix}/{SESSION_PREFIX}{session_id}/"
	return f"{SESSION_PREFIX}{session_id}/"

Related Issues

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions