#16026·LibreChat

[Bug]: rag_api /query returns 500 when the query string is empty (embeddings 400)

Author: wichtkingCreated Sep 16, 2026Updated Sep 16, 2026

What happened?

A chat turn on an agent with file search failed with 500 end to end: LibreChat reported Error creating context The server responded with status 500 on POST /api/agents, and rag_api logged an unhandled exception in query_embeddings_by_file_id because the incoming query string was empty:

Error in query embeddings | File ID: 26263cb6-... | Query:  | Error: Error code: 400 - {'detail': 'input must be a non-empty string or list'}

The empty query reaches the embeddings client unchecked, the provider answers 400, and the handler converts that into a 500 for LibreChat. The helper has no guard for an empty string:

python
# app/routes/document_routes.py
def get_cached_query_embedding(query: str):
    return vector_store.embedding_function.embed_query(query)     # line 540

@router.post("/query")                                            # line 543
async def query_embeddings_by_file_id(...):
    ...
    embedding = get_cached_query_embedding(body.query)            # line 551  <- empty string
    query_filter = scope.predicate(file_clause(body.file_id))

embed_query("")openai.BadRequestError: 400 input must be a non-empty string or list → uncaught → 500.

Expected: an empty/whitespace query should be rejected with a 4xx that names the problem (or the call skipped), not surfaced as a server error — today the caller only sees 500 with no way to tell a malformed request from a broken backend.

Version Information

LibreChat: v0.8.8-rc2
rag_api image: ghcr.io/danny-avila/librechat-rag-api-dev-lite@sha256:f9f34c8ed6884b0ff9b17387e6174fed737dba29f21622ecb75604d82bc47bf8
Embeddings: OpenAI-compatible endpoint (a self-hosted shim that rejects empty input with that 400 message)
Vector store: pgvector (pgvector/pgvector:0.8.0-pg15-trixie)
Node.js: v24.16.0 (LibreChat image)
MongoDB: 8.0
Deployment: docker compose, agents + file_search capability enabled

Steps to Reproduce

I could not reduce it to a deterministic step yet, and I could not call the endpoint in isolation because it requires a LibreChat-issued JWT (401 Missing or invalid Authorization header when called directly inside the container network), which I did not want to forge. What the logs do show:

  1. Agents with file_search enabled are in use.
  2. A turn produced [agents:graph] Empty messages after pruning in the LibreChat log.
  3. In the same second, rag_api received /query with an empty query for three different file IDs, each failing identically.
  4. LibreChat logged POST /api/agents500 (Error creating context).

So the likely trigger is a turn where the message text seen by the file-search step is empty (an empty message, or one that was pruned) while one or more files are still in scope. A minimal reproduction would be: send an empty message (or a message that gets pruned) to an agent that has file search enabled and at least one file attached.

Two questions a maintainer can answer from the code faster than I can from outside:

  • Does the file-search tool send the model-supplied query argument through unchanged (i.e. the model can send ""), or is the query built from the conversation text (i.e. pruning can empty it)?
  • Should the guard live in document_routes.py, or should LibreChat avoid calling with an empty query?

Relevant log output

rag_api (trimmed to the frames that matter; the traceback repeated three times, one per file ID):

Error in query embeddings | File ID: 26263cb6-0c36-4abe-bf92-66e20a688ce6 | Query:  |
Error: Error code: 400 - {'detail': 'input must be a non-empty string or list'}
Traceback (most recent call last):
  File "/app/app/routes/document_routes.py", line 551, in query_embeddings_by_file_id
    embedding = get_cached_query_embedding(body.query)
  File "/app/app/routes/document_routes.py", line 540, in get_cached_query_embedding
    return vector_store.embedding_function.embed_query(query)
  File "langchain_openai/embeddings/base.py", line 805, in embed_query
    return self.embed_documents([text], **kwargs)[0]
  ...
openai.BadRequestError: Error code: 400 - {'detail': 'input must be a non-empty string or list'}
HTTP Request: POST http://<embeddings-host>:8080/v1/embeddings "HTTP/1.1 400 Bad Request"

LibreChat:

{"level":"error","message":"[agents:graph] Empty messages after pruning","timestamp":"2026-09-16T16:15:00.202Z"}
{"level":"error","message":"Error creating context The server responded with status 500: Request failed with status code 500",
 "request_method":"POST","request_path":"/api/agents","status":500,"timestamp":"2026-09-16T16:16:20.184Z"}
{"level":"error","message":"[api/server/controllers/agents/client.js #sendCompletion] Unhandled error type",
 "request_method":"POST","request_path":"/api/agents","timestamp":"2026-09-16T16:15:00.211Z"}

What browsers are you seeing the problem on?

Server-side. Observed with Chrome 152 as the client; not browser-specific.