[Bug Report] Uncaught AttributeError (HTTP 500) in ForkEnvHandler when prev_eid or eid is missing
Bug Description
In py/visdom/server/handlers/web_handlers.py, ForkEnvHandler.wrap_func passes args.get("prev_eid") and args.get("eid") directly to escape_eid() without verifying that both fields are provided in the request payload:
class ForkEnvHandler(BaseHandler):
@staticmethod
async def wrap_func(handler, args):
prev_eid = escape_eid(args.get("prev_eid"))
eid = escape_eid(args.get("eid"))When a request to POST /fork_env omits either prev_eid or eid (or passes null), escape_eid(None) attempts to execute eid.strip(). This immediately raises an uncaught AttributeError: 'NoneType' object has no attribute 'strip'.
Because this exception is unhandled, Tornado catches it at the application boundary and responds with HTTP 500 Internal Server Error instead of returning a clean client error (HTTP 400 Bad Request).
In contrast, other handlers in web_handlers.py guard against None before calling escape_eid (e.g., DeleteEnvHandler checks if eid is None: return None, and EnvStateHandler checks if eid is not None:).
Reproduction Steps Enter steps to reproduce the behavior:
- Start the Visdom server (
python -m visdom.server). - Send a POST request to
/fork_envwithprev_eidmissing:Or send a POST request withcurl -i -X POST http://localhost:8097/fork_env \ -H "Content-Type: application/json" \ -d '{"eid": "new_env"}'eidmissing:curl -i -X POST http://localhost:8097/fork_env \ -H "Content-Type: application/json" \ -d '{"prev_eid": "main"}' - Observe the response: HTTP 500 Internal Server Error.
Expected behavior
ForkEnvHandler should validate that both prev_eid and eid are provided in the request body as strings. If either field is missing, null, or of invalid type, the server should return HTTP 400 Bad Request (e.g. raise tornado.web.HTTPError(400, reason="both 'prev_eid' and 'eid' must be strings")) rather than crashing with an unhandled 500.
Screenshots N/A (backend REST endpoint validation issue)
Client logs: N/A (applies to HTTP API requests)
Server logs:
Uncaught exception POST /fork_env (127.0.0.1)
HTTPServerRequest(protocol='http', host='127.0.0.1:8097', method='POST', uri='/fork_env', version='HTTP/1.1', remote_ip='127.0.0.1')
Traceback (most recent call last):
File ".../site-packages/tornado/web.py", line 1886, in _execute
result = await result
File "py/visdom/server/handlers/web_handlers.py", line 638, in post
await self.wrap_func(self, args)
File "py/visdom/server/handlers/web_handlers.py", line 604, in wrap_func
prev_eid = escape_eid(args.get("prev_eid"))
File "py/visdom/utils/server_utils.py", line 493, in escape_eid
eid.strip()
AttributeError: 'NoneType' object has no attribute 'strip'
ERROR:tornado.access:500 POST /fork_env (127.0.0.1) 2.85msAdditional context
According to openapi.yaml (lines 368–376), both prev_eid and eid are marked as required fields:
schema:
type: object
required: [prev_eid, eid]
properties:
prev_eid:
type: string
eid:
type: stringAdding an explicit validation check in ForkEnvHandler.wrap_func:
prev_eid = args.get("prev_eid")
eid = args.get("eid")
if not isinstance(prev_eid, str) or not isinstance(eid, str):
raise tornado.web.HTTPError(
400, reason="both 'prev_eid' and 'eid' must be strings"
)prevents the crash and ensures alignment with the OpenAPI specification and standard REST behavior.
Source: fossasia/visdom