Skip to content

Xorq infinite_request path leaks full traceback in error_info regardless of BUCKAROO_DEBUG #798

Description

@paddymul

Summary

handle_infinite_request_xorq in buckaroo/server/xorq_loading.py:89 unconditionally puts traceback.format_exc() into the response payload's error_info field. The pandas-path handler in websocket_handler.py:243 correctly gates this behind _BUCKAROO_DEBUG and ships "Request failed" to clients in production. The xorq path doesn't — so any handler exception leaks internal source paths, line numbers, and stack frames to the WS client.

Reproduction

ws = await tornado.websocket.websocket_connect("ws://127.0.0.1:8700/ws/boston")
await ws.read_message()  # initial state
ws.write_message(json.dumps({"type":"infinite_request","payload_args":{
    "start":100, "end":50, "sourceName":"default", "origEnd":50}}))
resp = json.loads(await ws.read_message())
assert resp["error_info"].startswith("Traceback")  # leaks

Observed on the boston xorq session — start=100, end=50 triggers an exception in the slice path, the response body carries:

'error_info': 'Traceback (most recent call last):\n  File "/Users/paddy/code/buckaroo/buckaroo/server/xorq_loading.py", line 86 ...'

Diff

buckaroo/server/xorq_loading.py:89-91:

    except Exception:
        return ({"type": "infinite_resp", "key": payload_args, "data": [],
            "length": 0, "error_info": traceback.format_exc()}, b"")

vs. the pandas WS handler at websocket_handler.py:241-245:

    except Exception:
        tb = traceback.format_exc()
        log.error("infinite_request error session=%s: %s", self.session_id, tb)
        self.write_message(json.dumps({"type": "infinite_resp", "key": payload_args, "data": [], "length": 0,
            "error_info": tb if _BUCKAROO_DEBUG else "Request failed"}))

Note also: the xorq path doesn't log.error the traceback server-side, so an operator running a non-debug server has no record of the error. The pandas path logs it correctly.

Suggested fix

Mirror the pandas-side pattern in handle_infinite_request_xorq:

import os
_BUCKAROO_DEBUG = os.environ.get("BUCKAROO_DEBUG", "").lower() in ("1", "true")
...
    except Exception:
        tb = traceback.format_exc()
        log = logging.getLogger("buckaroo.server.xorq_loading")
        log.error("xorq infinite_request error: %s", tb)
        return ({"type": "infinite_resp", "key": payload_args, "data": [],
            "length": 0, "error_info": tb if _BUCKAROO_DEBUG else "Request failed"}, b"")

Even cleaner: lift the error-handling out of the per-backend handlers, let the WS handler's outer try/except handle it uniformly. That eliminates the duplication.

Test plan

  • Failing-test commit: a Tornado WS test against a xorq session that triggers the exception path (e.g. start > end), asserts error_info does NOT start with "Traceback" unless BUCKAROO_DEBUG=1 is set in env.
  • Fix commit: gate by _BUCKAROO_DEBUG, log the traceback server-side.
  • Regression: existing tests pass; debug runs still see the full traceback.

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions