OpenHands / OpenHands/enterprise

DELETE /api/v1/sandboxes/{id}: path/handler param mismatch makes `sandbox_id` a required query param (and ignores the path)

Open Beginner friendly
#39 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
4
Forks
2
Avg merge
1d 22h
Merged PRs (30d)
101

Description

Summary

The DELETE /api/v1/sandboxes/{id} route's path parameter ({id}) does not match its handler's argument name (sandbox_id). Since FastAPI binds path parameters by name, {id} is never bound and sandbox_id is instead treated as a required query parameter. As a result:

  • DELETE /api/v1/sandboxes/<id>422 Unprocessable Entity (sandbox_id query field required)
  • DELETE /api/v1/sandboxes/<id>?sandbox_id=<id>200 (the path segment is ignored; only the query value is used)

The sibling routes POST /{sandbox_id}/pause and POST /{sandbox_id}/resume are correct (their path placeholder matches the handler arg sandbox_id), so only delete_sandbox is affected.

Affected code

openhands/app_server/sandbox/sandbox_router.py (main @ 7b228db):
https://github.com/OpenHands/OpenHands/blob/7b228db6ae143598b4caf65c6f7ed759b511f922/openhands/app_server/sandbox/sandbox_router.py#L108-L116

@router.delete('/{id}', responses={404: {'description': 'Item not found'}})
async def delete_sandbox(
    sandbox_id: str,        # <-- arg name does not match the path param '{id}'
    sandbox_service: SandboxService = sandbox_service_dependency,
) -> Success:
    exists = await sandbox_service.delete_sandbox(sandbox_id)
    if not exists:
        raise HTTPException(status.HTTP_404_NOT_FOUND)
    return Success()

Compare pause_sandbox / resume_sandbox immediately above, which use '/{sandbox_id}/...' and bind correctly.

Reproduction

$ curl -i -X DELETE http://localhost:3000/api/v1/sandboxes/oh-agent-server-XXXX
HTTP/1.1 422 Unprocessable Entity
{"detail":[{"type":"missing","loc":["query","sandbox_id"],"msg":"Field required","input":null}]}

$ curl -i -X DELETE "http://localhost:3000/api/v1/sandboxes/oh-agent-server-XXXX?sandbox_id=oh-agent-server-XXXX"
HTTP/1.1 200 OK
{"success":true}

Impact

  • A REST client calling the route as documented (id in the path, per the OpenAPI schema and RESTful convention) gets a 422 and cannot delete a sandbox without discovering the undocumented query param.
  • The generated OpenAPI schema is misleading: it advertises a {id} path param that is ignored, plus a required sandbox_id query param.
  • Because the path value is unused, DELETE /sandboxes/A?sandbox_id=B deletes B, not A.

Suggested fix

Rename the path parameter to match the handler argument (consistent with the pause/resume routes):

@router.delete('/{sandbox_id}', responses={404: {'description': 'Item not found'}})
async def delete_sandbox(
    sandbox_id: str,
    ...

(or, alternatively, rename the handler arg to id).

Environment

  • openhands 1.8.0, self-hosted V1 app-server (docker.openhands.dev/openhands/openhands:latest), Docker runtime, observed on localhost:3000.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in openhands/app_server/sandbox/sandbox_router.py around lines 108-116 and compare delete_sandbox with the pause_sandbox and resume_sandbox routes. Reproduce the DELETE requests from the issue, then verify that the documented path parameter is bound and the path value, rather than a query parameter, selects the sandbox.

Written by the indexing model from the issue text.

Assessment

Tech stack
fastapi, python
Domain
api, backend
Issue type
Bug
Difficulty
1/5
Estimated time
Under an hour
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
88/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.