Context
#378 fixed the import-time genai.Client(api_key=os.getenv("GEMINI_API_KEY", "")) in services/rag_service.py. Two instances of the same pattern remain — found while implementing #378/#379 (PR #411).
genai.Client(api_key="") raises ValueError at construction, so the empty-string fallback is never survivable.
1. backend/routes/documents.py:1091 — silently disables RAG indexing
_gclient=_genai.Client(api_key=os.getenv("GEMINI_API_KEY", ""))This sits inside _index_document_chunks (defined at :1047), within the try: at :1067 whose handler at :1127 is a broad except Exception: logger.exception(...). So without a key the ValueError is caught and the document upload still reports success while its RAG index is never built — a partial failure that looks like a clean one at the API boundary.
This is why tests/test_document_indexing.py::test_happy_path_indexes_chunks_when_no_catalog_embedding fails in a keyless run.
2. backend/scripts/ingest_catalog.py:41 — module-level
_gemini=genai.Client(api_key=os.getenv("GEMINI_API_KEY", ""))Same shape, constructed at import. Not on the import main graph, so it does not block app startup.
Severity
Low in production: config.validate_config() fail-closes on a missing GEMINI_API_KEY at startup, so neither path is reachable in a correctly-configured deploy. The cost is to local/keyless development and to the honesty of the error — the documents.py case degrades silently rather than loudly.
Scope
- Align both with the
"dummy-key-for-import" fallback used by services/gemini_service.py, agents/_providers.py, and now services/rag_service.py — or make the documents.py client lazy. - Consider narrowing the
except Exception at documents.py:1127 so a configuration error is not indistinguishable from a transient indexing failure. - No behavior change when a real key is present.
Acceptance criteria
Follow-up from #378 / PR #411. Related: #402.
Context
#378 fixed the import-time
genai.Client(api_key=os.getenv("GEMINI_API_KEY", ""))inservices/rag_service.py. Two instances of the same pattern remain — found while implementing #378/#379 (PR #411).genai.Client(api_key="")raisesValueErrorat construction, so the empty-string fallback is never survivable.1.
backend/routes/documents.py:1091— silently disables RAG indexingThis sits inside
_index_document_chunks(defined at :1047), within thetry:at :1067 whose handler at :1127 is a broadexcept Exception: logger.exception(...). So without a key theValueErroris caught and the document upload still reports success while its RAG index is never built — a partial failure that looks like a clean one at the API boundary.This is why
tests/test_document_indexing.py::test_happy_path_indexes_chunks_when_no_catalog_embeddingfails in a keyless run.2.
backend/scripts/ingest_catalog.py:41— module-levelSame shape, constructed at import. Not on the
import maingraph, so it does not block app startup.Severity
Low in production:
config.validate_config()fail-closes on a missingGEMINI_API_KEYat startup, so neither path is reachable in a correctly-configured deploy. The cost is to local/keyless development and to the honesty of the error — the documents.py case degrades silently rather than loudly.Scope
"dummy-key-for-import"fallback used byservices/gemini_service.py,agents/_providers.py, and nowservices/rag_service.py— or make thedocuments.pyclient lazy.except Exceptionatdocuments.py:1127so a configuration error is not indistinguishable from a transient indexing failure.Acceptance criteria
genai.Client(api_key=os.getenv("GEMINI_API_KEY", ""))in the tree (/usr/bin/grep -rn 'GEMINI_API_KEY", ""' backend/returns nothing).test_document_indexing.py::test_happy_path_indexes_chunks_when_no_catalog_embeddingpasses in a keyless run.Follow-up from #378 / PR #411. Related: #402.