Skip to content

Conversation

@devin-ai-integration
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot commented Oct 16, 2025

Describe your changes

Fixes SDK-510

This PR adds validation to provide better error feedback when users forget to return their ASGI/WSGI app instance from @asgi_app() or @wsgi_app() decorated functions.

Problem: When users forgot the return statement, they previously got a confusing runtime error TypeError: 'NoneType' object is not callable that appeared to be an internal Modal error.

Solution: Added validation in construct_webhook_callable immediately after calling the user's function to check if the return value is callable, and raise a clear InvalidError if it's not.

Changes:

  • Modified modal/_runtime/user_code_imports.py: Added validation for both ASGI and WSGI apps with clear error messages
  • Added test coverage in test/webhook_test.py: Two new test cases verify error handling for missing return statements

Error message example:

Function decorated with @asgi_app() must return a callable ASGI application, 
but returned NoneType. Did you forget to add a return statement?

Requested by: Eric Hansander (@ehdr)
Link to Devin run: https://app.devin.ai/sessions/68b9bc35d4b64951bdfb15cf3befb08d

Checklists

Compatibility checklist

  • Client+Server: this change is compatible with old servers (only affects client-side validation)
  • Client forward compatibility: N/A - no data format changes

Release checklist

  • Version file update not needed (minor fix)
  • Changelog - to be added if included in release

Human Review Checklist

  • Verify the callable() check is sufficient for validating ASGI/WSGI apps (per requirements, deep ASGI compliance checking was explicitly not requested)
  • Confirm error messages are clear and helpful for users
  • Verify test approach correctly simulates the container execution path where validation occurs
  • Check that both ASGI and WSGI apps are handled consistently

Changelog

  • Improved error messages for @asgi_app() and @wsgi_app() decorators when users forget to return their app instance. The error now clearly indicates the type returned and suggests adding a return statement.

Note

Adds validation to ensure @asgi_app() and @wsgi_app() functions return a callable, raising InvalidError with a clear message when missing.

  • Runtime:
    • Validate return of @asgi_app() and @wsgi_app() in modal/_runtime/user_code_imports.py by checking callability and raising InvalidError with explicit guidance when not callable (e.g., missing return).
  • Tests:
    • Add test_asgi_app_missing_return and test_wsgi_app_missing_return in test/webhook_test.py to assert clear errors for non-callable returns.

Written by Cursor Bugbot for commit 7fcdffc. This will update automatically on new commits. Configure here.

…_app() decorators

- Validate that user functions decorated with @asgi_app() return callable ASGI applications
- Validate that user functions decorated with @wsgi_app() return callable WSGI applications
- Provide clear error messages indicating the type returned and suggesting the user may have forgotten a return statement
- Add test coverage for both ASGI and WSGI missing return scenarios

Fixes SDK-510

Co-Authored-By: Eric Hansander <[email protected]>
@devin-ai-integration
Copy link
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

The tests were trying to import FastAPI and Flask which aren't available in the test environment. Changed to simple functions that return None to test the validation logic.

Co-Authored-By: Eric Hansander <[email protected]>
asgi_app = user_defined_callable()
if not callable(asgi_app):
raise InvalidError(
f"Function decorated with @asgi_app() must return a callable ASGI application, "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

References to Modal names in user-facing messages should always be fully-qualified.

Comment on lines 223 to 224
@pytest.mark.asyncio
async def test_asgi_app_missing_return(servicer, client, monkeypatch):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a huge test for a minor feature. Can it be simplified?

… tests

- Updated error messages to use 'modal.asgi_app()' and 'modal.wsgi_app()' instead of '@asgi_app()' and '@wsgi_app()'
- Simplified test cases by combining multiple assertions into single regex match
- Removed unused monkeypatch parameter and unnecessary module_name/function_name in test setup

Co-Authored-By: Eric Hansander <[email protected]>
@devin-ai-integration
Copy link
Contributor Author

Thanks for the feedback! I've addressed both comments:

  1. Fully-qualified decorator names: Updated error messages to use modal.asgi_app() and modal.wsgi_app() instead of @asgi_app() and @wsgi_app()

  2. Simplified tests: Reduced the test size significantly by:

    • Combining the three separate assertions into a single regex match that validates all key parts of the error message
    • Removing unnecessary test setup (module_name, function_name fields)
    • Removing unused monkeypatch parameter

The tests are now much more concise while still verifying the important aspects of the error message (decorator name, "callable", returned type "NoneType", and the helpful hint).

if not callable(asgi_app):
raise InvalidError(
f"Function decorated with @asgi_app() must return a callable ASGI application, "
f"Function decorated with modal.asgi_app() must return a callable ASGI application, "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You made the name fully qualified but you removed the decorator operator, which is useful here.

Updated error messages to use '@modal.asgi_app()' and '@modal.wsgi_app()' format to maintain the decorator operator while still using fully-qualified names.

Co-Authored-By: Eric Hansander <[email protected]>
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.

2 participants