odysseus-dev/odysseus · error · ValueError

Referenced upload is no longer available: {missing_upload_id

Error message

Referenced upload is no longer available: {missing_upload_id}

What it means

ValueError raised when persisting a new chat message: reserve_message_upload_references walks the message content/metadata for upload attachment references and finds an upload id that no longer exists (or is not owned by the session owner). This fails the write closed so transcripts never reference deleted uploads.

Source

Thrown at core/session_manager.py:248

        db = SessionLocal()
        try:
            db_session = db.query(DbSession).filter(DbSession.id == session_id).first()
            if db_session is None:
                # A stream/tool callback can outlive a session delete. Do not
                # create a chat_messages row with no parent session; also drop
                # any stale cached session so later writes fail closed too.
                self.sessions.pop(session_id, None)
                logger.warning("Dropping message for deleted session %s", session_id)
                return

            missing_upload_id = reserve_message_upload_references(
                getattr(self, "upload_handler", None),
                getattr(db_session, "owner", None),
                message.content,
                message.metadata,
            )
            if missing_upload_id:
                raise ValueError(
                    f"Referenced upload is no longer available: {missing_upload_id}"
                )

            msg_id = str(uuid.uuid4())
            msg_time = datetime.utcnow()
            if message.metadata is None:
                message.metadata = {}
            message.metadata.setdefault('timestamp', _message_timestamp_iso(msg_time))
            # Multimodal content may contain provider data URLs for the live
            # model call. Persist only readable text plus attachment references
            # so chat_messages/FTS do not duplicate upload bytes.
            _content = persistable_message_content(message.content, message.metadata)
            db_message = DbChatMessage(
                id=msg_id,
                session_id=session_id,
                role=message.role,
                content=_content,
                meta_data=json.dumps(message.metadata) if message.metadata else None,

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. Re-upload the file and send a new message referencing the fresh upload id
  2. If cleanup is racing active chats, exclude recently-referenced uploads from retention rules
  3. Verify the session owner matches the upload owner when sharing contexts across accounts
  4. On the client, drop stale attachment references before retrying the send

Example fix

# before
session_manager.add_message(session_id, message)  # references deleted upload
# after — prune dead references first
alive = [u for u in message.metadata.get('uploads', []) if upload_handler.get(u['id'])]
message.metadata['uploads'] = alive
session_manager.add_message(session_id, message)
Defensive patterns

Strategy: validation

Validate before calling

upload_ids = [u.get('id') for u in (message.metadata or {}).get('uploads', [])]
missing = [i for i in upload_ids if not upload_handler.get(i)]
if missing:
    raise ClientVisibleError(f'Attachments no longer available: {missing}')

Try / catch

try:
    sm.add_message(session_id, message)
except ValueError as e:
    if 'no longer available' in str(e):
        strip_dead_uploads(message)
        sm.add_message(session_id, message)  # retry without stale refs
    else:
        raise

Prevention

When it happens

Trigger: Sending/adding a message that references an upload id which was deleted by cleanup or another session, or an upload owned by a different user than db_session.owner. Raised inside add_message/persist before the row is inserted.

Common situations: Long-lived chat tab after uploads were pruned by retention/cleanup; upload deleted from another device; owner mismatch after account or session ownership changes; replaying old client state after server-side purge.

Related errors


AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14). Data as JSON: /api/errors/35dddb2d4b54a5d7. Report an issue: GitHub.