When handling failures, avoid broad try/except that hides root causes. Catch only the exceptions you expect, log a warning (with enough context to debug), and preserve the original error/stack trace. For unsupported/unimplemented functionality or dependency/version mismatches, fail explicitly with clear, actionable error messages.

Practical rules:

Example pattern:

import json
import logging
logger = logging.getLogger(__name__)

async def try_text2gql(text, intent_interpreter, text2cypher, graph_adapter):
    try:
        intention = await intent_interpreter.translate(text)
        interaction = await text2cypher.translate(json.dumps(intention))
        query = interaction.get("query", "")
        if "LIMIT" not in query:
            query += " LIMIT 10"
        return graph_adapter.query(query=query)
    except (KeyError, ValueError) as e:  # expected failures only
        logger.warning("text2gql failed; falling back. text=%r err=%s", text, e)
        return None

This keeps behavior predictable, makes production issues diagnosable, and ensures that truly unexpected bugs are not masked.