Skip to lesson
supraj.dev THE ENGINEERING HANDBOOKS
LEARN / BUILD / VERIFY2026 edition · checked 06 Oct

CHAPTER 13 / 30 · State, context and control

State is not a tenant boundary

Separate conversation state, application state and authenticated identity before serving multiple users.

4 min read + practiceWorked exerciseInterview practice

The mechanism

An agent may retain messages and application state between calls. That continuity is useful for follow-up questions, but it creates a security and correctness obligation: the state must belong to the right conversation and principal. Reusing one mutable object for unrelated users can mix context even when every individual tool call looks valid.

ParcelOps needs three distinct identifiers. A request ID correlates one operation, a session ID groups a conversation, and a tenant ID constrains resource access. They have different lifetimes and must not be interchangeable. A user-supplied session string is not proof that the caller owns the corresponding conversation.

Authenticated principal
Authorized session lookup
Request-scoped agent context
Tenant-scoped data access

A worked identity envelope

This is an application design example, not a Strands constructor option. Trusted middleware creates the envelope after authentication. The model receives only the fields needed for its task.

{
  "request_id": "req-demo-001",
  "session_id": "session-demo-a",
  "principal_id": "operator-demo",
  "tenant_id": "tenant-demo",
  "allowed_operations": ["incident:read"],
  "policy_revision": "training-policy-1"
}

The authenticated principal, allowed operations and policy revision should never be accepted from model-generated tool arguments. A tool may accept an incident ID; the application resolves the tenant scope from this trusted context. This prevents a model from expanding access by supplying a different tenant_id.

State also differs from evidence. A cached statement that “INC-104 was delayed” may help continuity, but a current operational answer should check freshness against the source. Storing a value in agent state does not make it authoritative or permanent. Treat mutable state as application data with ownership and validation rules.

Practice: find the cross-session leak

Offline. Imagine a global current_tenant variable shared by two requests. Request A sets it to tenant A, pauses for a model response, and request B changes it to tenant B. When A’s tool runs, which tenant does it read? Draw the interleaving explicitly.

Expected observation: a sequential test can pass while concurrency reveals the leak. Replace mutable global identity with request-scoped context and a destination authorization check. Then design a test that interleaves two synthetic tenants and asserts that each sees only its own fixture records.

Add a second test in which the caller supplies another user’s session ID. The server should reject or conceal that session before constructing the agent context. Finally, decide whether an operator can intentionally switch tenants, and require that switch to pass the same authenticated authorization path.

Troubleshooting and trade-offs

Unexpected references to an earlier user’s task may indicate reused conversation state, shared caches or incorrectly keyed storage. Inspect ownership and key construction before blaming model memory. A session ID with high entropy reduces guessing but does not replace access checks.

Concurrent invocation features in a modern SDK do not automatically authorize every conversation correctly. Your storage backend, tools and application context still need isolation. Keep tests at both levels: SDK integration behavior and end-to-end tenant boundaries.

Avoid persisting arbitrary Python objects merely because a state API accepts a dictionary. Choose a versioned, serializable contract and define migration and deletion behavior. Small explicit state is easier to inspect after an incident than a large opaque object graph.

Interview practice

Why are request, session and tenant IDs separate?

They represent one operation, a conversation and an authorization domain. Their lifetimes and permissions differ. Mixing them can cause data leakage, incorrect retries or unauthorized session access.

Does a concurrency-safe SDK make shared application globals safe?

No. SDK concurrency behavior does not repair mutable global identity, incorrectly keyed caches or destination authorization. Those are application responsibilities that require interleaving tests.

Completion check

Draw two simultaneous users and show where their state is separated. Explain how a tool gets trusted tenant identity without asking the model to provide it. Include an unauthorized-session test in your acceptance plan.

Sources and version notes

Checked 6 October 2026. Python examples target strands-agents==1.58.0 unless labelled otherwise. Live documentation can change; compare your installed version before adapting an example.

YOUR NEXT STEP

Make the understanding yours.

Use the completion check above. Mark this chapter when you can explain the mechanism and its limits.

Self-assessed reading progress. This does not certify that a lab ran or a system is secure.