fix(api): return 4xx not 500 when attachment blob is missing (#15509)

Guard the agent-attachment download against a missing or empty storage blob so the caller gets a structured 4xx (`Document not found!`) instead of an HTTP 500. Same bug class as #15365 on document preview.
Resolve #15502
This commit is contained in:
dripsmvcp
2026-06-15 00:41:49 -07:00
committed by GitHub
parent 0480dee83f
commit 53d4d9b3bd
2 changed files with 219 additions and 1 deletions

View File

@@ -2357,7 +2357,7 @@ async def download_attachment(tenant_id=None, attachment_id=None):
Mirrors the authorization model of the preview endpoint: the user must belong
to the tenant that owns the document's knowledge base. A denial returns the
same "Document not found!" response so the endpoint cannot be used to
same "Attachment not found!" response so the endpoint cannot be used to
enumerate doc ids across tenants.
"""
try:
@@ -2365,6 +2365,15 @@ async def download_attachment(tenant_id=None, attachment_id=None):
# pass `attachment_id` instead of the route parameter name.
ext = request.args.get("ext", "markdown")
data = await thread_pool_exec(settings.STORAGE_IMPL.get, tenant_id, attachment_id)
if not data:
# Storage object missing or empty (orphaned DB metadata, tenant
# mismatch). Without this guard `make_response(None)` raises
# `TypeError: response value cannot be None` and the caller
# sees HTTP 500 — same bug class as #15365 on document
# preview. Return the same "Attachment not found!" shape used
# by the preview route's missing-record path so byte-streaming
# endpoints respond consistently on a not-found.
return get_data_error_result(message="Attachment not found!")
response = await make_response(data)
content_type = CONTENT_TYPE_MAP.get(ext, f"application/{ext}")
apply_safe_file_response_headers(response, content_type, ext)