Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions src/runpod_flash/runtime/generic_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,17 @@ def handler(job: Dict[str, Any]) -> Dict[str, Any]:
Returns:
Response dict with 'success', 'result'/'error' keys
"""
job_input = job.get("input", {})
raw_input = job.get("input")
if raw_input is None:
job_input = {}
elif not isinstance(raw_input, dict):
return {
"success": False,
"error": f"Invalid job input type: expected dict, got {type(raw_input).__name__}",
"traceback": "",
}
else:
job_input = raw_input
function_name = job_input.get("function_name")
execution_type = job_input.get("execution_type", "function")

Expand Down Expand Up @@ -227,7 +237,14 @@ def create_deployed_handler(func: Callable) -> Callable:
"""

def handler(job: Dict[str, Any]) -> Any:
job_input = job.get("input", {})
if "input" not in job or job.get("input") is None:
job_input = {}
else:
job_input = job.get("input")
if not isinstance(job_input, dict):
return {
"error": f"Malformed input: expected dict, got {type(job_input).__name__}",
}
try:
result = func(**job_input)
if inspect.iscoroutine(result):
Expand Down
76 changes: 76 additions & 0 deletions tests/unit/runtime/test_generic_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import cloudpickle

from runpod_flash.runtime.generic_handler import (
create_deployed_handler,
create_handler,
deserialize_arguments,
execute_function,
Expand Down Expand Up @@ -366,3 +367,78 @@ def returns_none():
assert response["success"] is True
result = cloudpickle.loads(base64.b64decode(response["result"]))
assert result is None


def test_create_handler_input_none():
"""Test handler returns error when job input is None instead of crashing."""

def dummy():
return "dummy"

handler = create_handler({"dummy": dummy})

job = {"input": None}

response = handler(job)
assert response["success"] is False
assert "not found" in response["error"]


def test_create_handler_input_missing():
"""Test handler returns error when job has no input key."""

def dummy():
return "dummy"

handler = create_handler({"dummy": dummy})

job = {}

response = handler(job)
assert response["success"] is False
assert "not found" in response["error"]


def test_create_handler_input_non_dict():
"""Test handler rejects non-dict input types."""

def dummy():
return "dummy"

handler = create_handler({"dummy": dummy})

job = {"input": "not a dict"}

response = handler(job)
assert response["success"] is False
assert "Invalid job input type" in response["error"]
assert "str" in response["error"]


def test_create_deployed_handler_input_none():
"""Test deployed handler treats None input as empty kwargs instead of crashing."""

def dummy(x: int = 1):
return x

handler = create_deployed_handler(dummy)

job = {"input": None}

result = handler(job)
assert result == 1


def test_create_deployed_handler_input_non_dict():
"""Test deployed handler rejects non-dict input types."""

def dummy(x: int = 1):
return x

handler = create_deployed_handler(dummy)

job = {"input": [1, 2, 3]}

result = handler(job)
assert "error" in result
assert "list" in result["error"]
Loading