Skip to content

fix(utils): re-raise in timed_with_status when no fallback configured#1524

Open
Ptah-CT wants to merge 1 commit intoMemTensor:mainfrom
Ptah-CT:fix/timed-with-status-silent-fail
Open

fix(utils): re-raise in timed_with_status when no fallback configured#1524
Ptah-CT wants to merge 1 commit intoMemTensor:mainfrom
Ptah-CT:fix/timed-with-status-silent-fail

Conversation

@Ptah-CT
Copy link
Copy Markdown

@Ptah-CT Ptah-CT commented Apr 22, 2026

Fixes #1523.

Problem

timed_with_status caught every exception, ran the optional fallback, but when no fallback was configured the wrapper fell through to an implicit return None. Decorated functions returned None on any failure instead of raising.

Concrete consequence: OpenAILLM.generate (decorated with this) returned None on a MiniMax 400 (chat content is empty (2013) for system-only messages), and the suggestion handler then died in clean_json_response with AttributeError: 'NoneType' object has no attribute 'replace'. The real 400 was hidden.

Change

Add a single raise after the fallback branch:

                if fallback is not None and callable(fallback):
                    result = fallback(e, *args, **kwargs)
                    return result
                # No fallback configured -> re-raise so callers see the failure
                # instead of receiving an implicit None. ...
                raise
            finally:
                ...

finally still runs, so the timing/status log line is unchanged.

Type

  • Bug fix (non-breaking change which fixes an issue)

Tested

  • Reproduced locally with MOS_CHAT_MODEL=MiniMax-M2.7, OPENAI_API_BASE=https://api.minimax.io/v1, system-only suggestion prompt.
    • Before: HTTP 500 'NoneType' object has no attribute 'replace'
    • After: HTTP 500 surfaces the real openai.BadRequestError: 400 ... invalid params, chat content is empty (2013) to the caller, exactly as [TIMER_WITH_STATUS] already logged.
  • Existing fallback path (fallback= arg supplied) is exercised by other handlers; behaviour unchanged because raise is reached only when no fallback returns.

Checklist

  • Self-review done
  • Comment added explaining the fix
  • Unit test added (existing test suite did not cover this branch; happy to add a small one if maintainers want it)
  • Linked to issue

The except branch in timed_with_status caught every exception, ran the
optional fallback if configured, but otherwise let the function fall
through to the implicit return None. Decorated functions like
OpenAILLM.generate then returned None on a 4xx/5xx without surfacing
the underlying error, and callers crashed later with confusing
AttributeErrors (e.g. clean_json_response receiving None).

Add an explicit `raise` so the failure propagates when no fallback is
configured. Existing fallback semantics are unchanged.

Repro: configure MOS_CHAT_MODEL=MiniMax-M2.7 with OPENAI_API_BASE
pointed at the MiniMax v1 endpoint, then POST /product/suggestions
with a body whose suggestion prompt contains only a system message.
MiniMax replies 400 'chat content is empty (2013)', the decorator
swallows the BadRequestError, generate() returns None, and
suggestion_handler then dies in clean_json_response with
'NoneType object has no attribute replace'. With this patch the
BadRequestError reaches the handler intact and the user sees the
real 400 instead of a misleading AttributeError.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] timed_with_status decorator silently swallows exceptions and returns None

2 participants