Skip to content

Archive Creation Fails with AttributeError on embedding Parameter #3073

@wsargent

Description

@wsargent

Describe the bug

The /v1/archives POST endpoint (create archive) crashes with an AttributeError when using the embedding parameter. The endpoint code incorrectly tries to access .provider and .model attributes on a string value.

Error:

AttributeError: 'str' object has no attribute 'provider'

Please describe your setup

  • How are you running Letta?
    • Docker (letta/letta:0.14.0)
  • Describe your setup
    • OS: macOS (Darwin 25.1.0)
    • Docker command: docker compose up with the following configuration:
      letta:
        image: letta/letta:0.14.0
        ports:
          - 8283:8283
        environment:
          LETTA_PG_DB: letta
          LETTA_PG_USER: letta
          LETTA_PG_PASSWORD: letta
          LETTA_PG_HOST: pgvector_db
          LETTA_PG_PORT: 5432
          ANTHROPIC_API_KEY: $ANTHROPIC_API_KEY
          GEMINI_API_KEY: $GEMINI_API_KEY

Screenshots

Full stack trace:

letta-1     | Letta.letta.server.rest_api.middleware.logging - ERROR - Unhandled exception in request: AttributeError: 'str' object has no attribute 'provider'
letta-1     | Traceback (most recent call last):
letta-1     |   File "/app/.venv/lib/python3.11/site-packages/starlette/middleware/base.py", line 151, in call_next
letta-1     |     message = await recv_stream.receive()
letta-1     |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^
letta-1     |   File "/app/.venv/lib/python3.11/site-packages/anyio/streams/memory.py", line 126, in receive
letta-1     |     raise EndOfStream from None
letta-1     | anyio.EndOfStream
letta-1     |
letta-1     | During handling of the above exception, another exception occurred:
letta-1     |
letta-1     | Traceback (most recent call last):
letta-1     |   File "/app/letta/server/rest_api/middleware/logging.py", line 81, in dispatch
letta-1     |     response = await call_next(request)
letta-1     |                ^^^^^^^^^^^^^^^^^^^^^^^^
letta-1     |   File "/app/.venv/lib/python3.11/site-packages/starlette/middleware/base.py", line 159, in call_next
letta-1     |     raise app_exc
letta-1     |   File "/app/.venv/lib/python3.11/site-packages/starlette/middleware/base.py", line 144, in coro
letta-1     |     await self.app(scope, receive_or_disconnect, send_no_error)
letta-1     |   File "/app/.venv/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 63, in __call__
letta-1     |     await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
letta-1     |   File "/app/.venv/lib/python3.11/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
letta-1     |     raise exc
letta-1     |   File "/app/.venv/lib/python3.11/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app
letta-1     |     await app(scope, receive, sender)
letta-1     |   File "/app/.venv/lib/python3.11/site-packages/starlette/routing.py", line 716, in __call__
letta-1     |     await self.middleware_stack(scope, receive, send)
letta-1     |   File "/app/.venv/lib/python3.11/site-packages/starlette/routing.py", line 736, in app
letta-1     |     await route.handle(scope, receive, send)
letta-1     |   File "/app/.venv/lib/python3.11/site-packages/starlette/routing.py", line 290, in handle
letta-1     |     await self.app(scope, receive, send)
letta-1     |   File "/app/.venv/lib/python3.11/site-packages/starlette/routing.py", line 78, in app
letta-1     |     await wrap_app_handling_exceptions(app, request)(scope, receive, send)
letta-1     |   File "/app/.venv/lib/python3.11/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
letta-1     |     raise exc
letta-1     |   File "/app/.venv/lib/python3.11/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app
letta-1     |     await app(scope, receive, sender)
letta-1     |   File "/app/.venv/lib/python3.11/site-packages/starlette/routing.py", line 75, in app
letta-1     |     response = await f(request)
letta-1     |                ^^^^^^^^^^^^^^^^
letta-1     |   File "/app/.venv/lib/python3.11/site-packages/fastapi/routing.py", line 302, in app
letta-1     |     raw_response = await run_endpoint_function(
letta-1     |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
letta-1     |   File "/app/.venv/lib/python3.11/site-packages/fastapi/routing.py", line 213, in run_endpoint_function
letta-1     |     return await dependant.call(**values)
letta-1     |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
letta-1     |   File "/app/letta/server/rest_api/routers/v1/archives.py", line 68, in create_archive
letta-1     |     handle = f"{archive.embedding.provider}/{archive.embedding.model}"
letta-1     |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
letta-1     | AttributeError: 'str' object has no attribute 'provider'

Additional context

  • This affects Letta version 0.14.0
  • Model used: letta/letta-free (free embedding model)
  • The deprecated embedding_config parameter still works but requires constructing a full EmbeddingConfig object
  • The bug prevents using the simpler string-based embedding parameter that was intended as the replacement

Root Cause

In letta/server/rest_api/routers/v1/archives.py:

# Line 30: embedding is defined as a string
class ArchiveCreateRequest(BaseModel):
    embedding: Optional[str] = Field(None, description="Embedding model handle for the archive")

# Lines 67-68: Code incorrectly treats it as an object
if embedding_config is None and archive.embedding is not None:
    handle = f"{archive.embedding.provider}/{archive.embedding.model}"  # ❌ Bug!

The embedding field is defined as Optional[str] (line 30), but the code on line 68 tries to access .provider and .model attributes as if it were an object.

Steps to Reproduce

Using the Letta Python client:

from letta_client import Letta

client = Letta(base_url="http://localhost:8283", token="your_token")

# This triggers the bug
archive = client.archives.create(
    name="test-archive",
    description="Test archive",
    embedding="letta/letta-free"
)

Expected Behavior

The archive should be created successfully using the string handle "letta/letta-free".

Suggested Fix

Since archive.embedding is already a string handle in the format "provider/model" (e.g., "letta/letta-free"), the code should use it directly:

Change line 68 in letta/server/rest_api/routers/v1/archives.py from:

handle = f"{archive.embedding.provider}/{archive.embedding.model}"

to:

handle = archive.embedding

Full corrected code block (lines 66-72):

embedding_config = archive.embedding_config
if embedding_config is None and archive.embedding is not None:
    handle = archive.embedding  # ✅ Fix: use the string directly
    embedding_config = await server.get_embedding_config_from_handle_async(
        handle=handle,
        actor=actor,
    )

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