From 8153ea35a4c8e37d6bc3fb674ca339ac579f24c3 Mon Sep 17 00:00:00 2001 From: David Blanc Brioir Date: Thu, 1 Jan 2026 15:10:06 +0100 Subject: [PATCH] fix: Prevent context manager conflict in hierarchical_search MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Problem "generator didn't stop after throw()" error when hierarchical_search falls back to simple_search. Both functions use 'with get_weaviate_client()', creating nested context managers on the same generator. ## Solution - Use ValueError("FALLBACK_TO_SIMPLE") signal instead of calling simple_search() inside the context manager - Catch ValueError in except block and call simple_search() outside context - Applied to all 3 fallback points: 1. No Weaviate client 2. No summaries found (Stage 1) 3. No sections after filtering ## Result Fallback now works correctly without context manager conflicts. πŸ€– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- generations/library_rag/flask_app.py | 50 ++++++++++++---------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/generations/library_rag/flask_app.py b/generations/library_rag/flask_app.py index 345ac38..d1016e0 100644 --- a/generations/library_rag/flask_app.py +++ b/generations/library_rag/flask_app.py @@ -317,16 +317,8 @@ def hierarchical_search( try: with get_weaviate_client() as client: if client is None: - # Fallback to simple search only if not forced - if not force_hierarchical: - results = simple_search(query, limit, author_filter, work_filter) - return { - "mode": "simple", - "results": results, - "total_chunks": len(results), - } - else: - # Forced hierarchical with no client + # Return early if forced, otherwise signal fallback + if force_hierarchical: return { "mode": "hierarchical", "sections": [], @@ -334,6 +326,8 @@ def hierarchical_search( "total_chunks": 0, "fallback_reason": "Weaviate client unavailable", } + # Set flag to fallback outside context manager + raise ValueError("FALLBACK_TO_SIMPLE") # ═══════════════════════════════════════════════════════════════ # STAGE 1: Search Summary collection for relevant sections @@ -352,15 +346,7 @@ def hierarchical_search( if not summaries_result.objects: # No summaries found - if not force_hierarchical: - # Auto-detection: fallback to simple search - results = simple_search(query, limit, author_filter, work_filter) - return { - "mode": "simple", - "results": results, - "total_chunks": len(results), - } - else: + if force_hierarchical: # Forced hierarchical: return empty hierarchical result return { "mode": "hierarchical", @@ -369,6 +355,8 @@ def hierarchical_search( "total_chunks": 0, "fallback_reason": f"Aucune section pertinente trouvΓ©e (0/{sections_limit} summaries)", } + # Signal fallback outside context manager + raise ValueError("FALLBACK_TO_SIMPLE") # Extract section data sections_data = [] @@ -418,15 +406,7 @@ def hierarchical_search( if not sections_data: # No sections match filters - if not force_hierarchical: - # Auto-detection: fallback to simple search - results = simple_search(query, limit, author_filter, work_filter) - return { - "mode": "simple", - "results": results, - "total_chunks": len(results), - } - else: + if force_hierarchical: # Forced hierarchical: return empty hierarchical result filters_str = f"author={author_filter}" if author_filter else "" if work_filter: @@ -438,6 +418,8 @@ def hierarchical_search( "total_chunks": 0, "fallback_reason": f"Aucune section ne correspond aux filtres ({filters_str})", } + # Signal fallback outside context manager + raise ValueError("FALLBACK_TO_SIMPLE") # ═══════════════════════════════════════════════════════════════ # STAGE 2: Search Chunk collection filtered by sections @@ -497,6 +479,18 @@ def hierarchical_search( "total_chunks": len(all_chunks), } + except ValueError as e: + # Check if this is our fallback signal + if str(e) == "FALLBACK_TO_SIMPLE": + # Fallback to simple search (outside context manager) + results = simple_search(query, limit, author_filter, work_filter) + return { + "mode": "simple", + "results": results, + "total_chunks": len(results), + } + # Re-raise if not our signal + raise except Exception as e: print(f"Erreur recherche hiΓ©rarchique: {e}") # Fallback to simple search on error (unless forced)