Return 4xx when file download storage blob is missing (#15371)

## Summary

Fixes [#15369](https://github.com/infiniflow/ragflow/issues/15369) —
`GET /api/v1/files/<file_id>` calls `make_response(None)` when both
primary and fallback storage lookups return empty, causing HTTP 500.

## Related Issue

Fixes #15369

## Change Type

- [x] Bug fix
- [x] Regression tests

## What Changed

- **`file_api.download()`** — after fallback `STORAGE_IMPL.get`, return
`get_error_data_result(message="This file is empty.")` when `not blob`,
matching document REST download semantics.

## Files Changed

| File | Change |
|------|--------|
| `api/apps/restful_apis/file_api.py` | Empty-blob guard before
`make_response()` |
| `test/testcases/test_web_api/test_file_app/test_file_routes_unit.py` |
Regression test |

## Validation

```bash
cd /root/gittensor/ragflow
pytest test/testcases/test_web_api/test_file_app/test_file_routes_unit.py::test_download_missing_blob_returns_error -v
pytest test/testcases/test_web_api/test_file_app/test_file_routes_unit.py::test_download_falls_back_to_document_storage -v
```

## Test Plan

- [x] Both storage paths empty → `"This file is empty."` (no
`make_response(None)`)
- [x] Existing fallback success test still passes
- [ ] CI green
This commit is contained in:
kpdev
2026-06-01 04:08:06 -07:00
committed by GitHub
parent f194e8b4c4
commit b35266e9a5
2 changed files with 23 additions and 0 deletions

View File

@@ -299,6 +299,13 @@ async def download(tenant_id: str = None, file_id: str = None):
if not blob:
b, n = File2DocumentService.get_storage_address(file_id=file_id)
blob = await thread_pool_exec(settings.STORAGE_IMPL.get, b, n)
if not blob:
logging.warning(
"Download failed: empty blob after primary+fallback lookup (tenant_id=%s, file_id=%s)",
tenant_id,
file_id,
)
return get_error_data_result(message="This file is empty.")
response = await make_response(blob)
ext = re.search(r"\.([^.]+)$", file.name.lower())

View File

@@ -327,6 +327,22 @@ def test_download_falls_back_to_document_storage(monkeypatch):
assert res.headers["ext"] == "txt"
@pytest.mark.p2
def test_download_missing_blob_returns_error(monkeypatch):
module = _load_file_api_module(monkeypatch)
storage_calls = []
def _get(bucket, location):
storage_calls.append((bucket, location))
return None
monkeypatch.setattr(module.settings, "STORAGE_IMPL", SimpleNamespace(get=_get))
res = _run(module.download("tenant1", "file1"))
assert storage_calls == [("bucket1", "path1"), ("bucket2", "path2")]
assert res["message"] == "This file is empty."
@pytest.mark.p2
def test_parent_and_ancestors_use_new_routes(monkeypatch):
module = _load_file_api_module(monkeypatch)