Skip to content

Returning empty object from handler raises KeyError exception within framework #459

@target-san

Description

@target-san

Describe the bug
When Runpod event handler returns empty object {}, KeyError is raised within runpod framework

To Reproduce
Steps to reproduce the behavior:

  1. Write minimal worker code:
    # Requirements:
    # - runpod@1.7.13
    import runpod
    
    def handler(event):
        return {}
    
    # Start the Serverless function when the script is run
    if __name__ == '__main__':
        runpod.serverless.start({'handler': handler})
  2. Run it: python worper.py --rp_serve_api
  3. Send request to worker: curl -X POST http://localhost:8000/runsync -H "Content-Type: application/json" -d '{"input": {}}'
  4. Observe "Internal Server Error" returned by client
  5. Observe exception within server code:
    ERROR:    Exception in ASGI application
    Traceback (most recent call last):
    File ".venv/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 409, in run_asgi
        result = await app(  # type: ignore[func-returns-value]
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File ".venv/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 60, in __call__
        return await self.app(scope, receive, send)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File ".venv/lib/python3.12/site-packages/fastapi/applications.py", line 1054, in __call__
        await super().__call__(scope, receive, send)
    File ".venv/lib/python3.12/site-packages/starlette/applications.py", line 113, in __call__
        await self.middleware_stack(scope, receive, send)
    File ".venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 186, in __call__
        raise exc
    File ".venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 164, in __call__
        await self.app(scope, receive, _send)
    File ".venv/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 63, in __call__
        await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
    File ".venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
        raise exc
    File ".venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app
        await app(scope, receive, sender)
    File ".venv/lib/python3.12/site-packages/starlette/routing.py", line 716, in __call__
        await self.middleware_stack(scope, receive, send)
    File ".venv/lib/python3.12/site-packages/starlette/routing.py", line 736, in app
        await route.handle(scope, receive, send)
    File ".venv/lib/python3.12/site-packages/starlette/routing.py", line 290, in handle
        await self.app(scope, receive, send)
    File ".venv/lib/python3.12/site-packages/starlette/routing.py", line 78, in app
        await wrap_app_handling_exceptions(app, request)(scope, receive, send)
    File ".venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
        raise exc
    File ".venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 42, in wrapped_app
        await app(scope, receive, sender)
    File ".venv/lib/python3.12/site-packages/starlette/routing.py", line 75, in app
        response = await f(request)
                ^^^^^^^^^^^^^^^^
    File ".venv/lib/python3.12/site-packages/fastapi/routing.py", line 302, in app
        raw_response = await run_endpoint_function(
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File ".venv/lib/python3.12/site-packages/fastapi/routing.py", line 213, in run_endpoint_function
        return await dependant.call(**values)
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    File ".venv/lib/python3.12/site-packages/runpod/serverless/modules/rp_fastapi.py", line 342, in _sim_runsync
        {"id": job.id, "status": "COMPLETED", "output": job_output["output"]}
                                                        ~~~~~~~~~~^^^^^^^^^^
    KeyError: 'output'
    

Expected behavior
Either, handler returns empty object as response output or provides clear and concise error message that empty object can't serve as handler output

Runpod SDK version
runpod@1.7.13

Screenshots
No screenshots

Desktop (please complete the following information):
SDK issue, not desktop

Smartphone (please complete the following information):
SDK issue, not smartphone

Additional context
The problem arises because FastAPI handler at

{"id": job.id, "status": "COMPLETED", "output": job_output["output"]}
unconditionally retrieves handler's output as job_output['output'], yet that same 'output' gets removed at
if run_result.get("output") == {}:
run_result.pop("output")
if it's an empty object

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions