Uncaught KeyError (HTTP 500) in CloseHandler and DataHandler for non-existent environments
Author: Pcmhacker-piroCreated Sep 14, 2026Updated Sep 14, 2026
Bug Description
In py/visdom/server/handlers/web_handlers.py, both CloseHandler (POST /close) and DataHandler (POST /win_data) access handler.state[eid] directly without checking whether eid exists in handler.state.
When a request is made for an environment that does not exist or is not loaded:
- In
CloseHandler.post:If the environment does not exist,await ensure_env_loaded(self, extract_eid(args)) self.wrap_func(self, args)ensure_env_loadedreturnsNoneimmediately. - In
CloseHandler.wrap_func:Whetherkeys = list(handler.state[eid]["jsons"].keys()) if win is None else [win] for win in keys: p_data = handler.state[eid]["jsons"].pop(win, None)winisNoneor a specific window name, accessinghandler.state[eid]immediately raises an unhandledKeyError: '<eid>'. - In
DataHandler.wrap_func(when reading window data):Accessingif "win" in args and args["win"] is None: handler.write(json.dumps(handler.state[eid]["jsons"], cls=NanSafeEncoder)) else: if args["win"] not in handler.state[eid]["jsons"]: raise tornado.web.HTTPError(400, reason="window doesn't exist in this env")handler.state[eid]raisesKeyError: '<eid>'before the window check can run.
Because this KeyError is uncaught, Tornado returns an HTTP 500 Internal Server Error instead of returning a 400/404 or gracefully no-opping. In contrast, other handlers like ExistsHandler and EnvStateHandler properly guard against missing environments with if eid in handler.state:.
Reproduction Steps
- Start the Visdom server (
python -m visdom.server). - Send a POST request to
/closetargeting a non-existent environment:Or to clear a non-existent env:curl -X POST http://localhost:8097/close \ -H "Content-Type: application/json" \ -d '{"eid": "nonexistent_env", "win": "w1"}'curl -X POST http://localhost:8097/close \ -H "Content-Type: application/json" \ -d '{"eid": "nonexistent_env"}' - Send a POST request to
/win_datafor a non-existent environment:curl -X POST http://localhost:8097/win_data \ -H "Content-Type: application/json" \ -d '{"eid": "nonexistent_env", "win": "w1"}' - Observe the response: HTTP 500 Internal Server Error.
Expected behavior
- Closing a window or clearing an environment that does not exist should gracefully succeed/no-op (
if eid not in handler.state: return), as there are no windows or state to delete. - Querying window data from an environment that does not exist should return HTTP 404 (e.g.
tornado.web.HTTPError(404, reason="environment '...' not found")) or HTTP 400 rather than crashing with 500.
Server logs:
ERROR:tornado.application:Uncaught exception POST /close (127.0.0.1)
HTTPServerRequest(protocol='http', host='localhost:8097', method='POST', uri='/close', version='HTTP/1.1', remote_ip='127.0.0.1')
Traceback (most recent call last):
File ".../tornado/web.py", line 1788, in _execute
result = method(*self.path_args, **self.path_kwargs)
File "py/visdom/server/handlers/web_handlers.py", line 538, in post
self.wrap_func(self, args)
File "py/visdom/server/handlers/web_handlers.py", line 523, in wrap_func
keys = list(handler.state[eid]["jsons"].keys()) if win is None else [win]
KeyError: 'nonexistent_env'Proposed Fix
In py/visdom/server/handlers/web_handlers.py:
- In
CloseHandler.wrap_func:
@staticmethod
def wrap_func(handler, args):
eid = extract_eid(args)
if eid not in handler.state:
return
win = args.get("win")
...- In
DataHandler.wrap_func:
@staticmethod
def wrap_func(handler, args):
eid = extract_eid(args)
if "data" in args:
...
else:
if eid not in handler.state:
if "win" in args and args["win"] is None:
handler.write(json.dumps({}, cls=NanSafeEncoder))
return
raise tornado.web.HTTPError(404, reason="environment '{}' not found".format(eid))
...Source: fossasia/visdom