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

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