-
Notifications
You must be signed in to change notification settings - Fork 140
Description
What happened?
Summary
The HTTP+JSON transport returns 415 Unsupported Media Type (ContentTypeNotSupportedError) on POST requests that lack a Content-Type: application/json header, even when the request body is empty. This affects POST /tasks/{id}:cancel and any other bodyless POST endpoint.
Requirement
- ID: CORE-CANCEL-001 / CORE-CANCEL-003 / HTTP_JSON-STATUS-001
- Section: 3.1.5 — CancelTask returns updated task with cancellation status
- Level: MUST
- Spec: https://github.com/a2aproject/A2A/blob/173695755607e884aa9acf8ce4feed90e32727a1/docs/specification.md#315-cancel-task
Specification
The operation attempts to cancel the specified task and returns its updated state.
Errors:
TaskNotCancelableError: The task is not in a cancelable state (e.g., already completed, failed, or canceled).TaskNotFoundError: The task ID does not exist or is not accessible.
The error code mappings table (Section 5.4) defines ContentTypeNotSupportedError as:
A Media Type provided in the request's message parts or implied for an artifact is not supported by the agent or the specific skill being invoked.
This error is intended for unsupported media types in message parts, not for missing Content-Type headers on bodyless requests.
Expected behavior
A POST /tasks/{id}:cancel request with no body should be accepted regardless of whether a Content-Type header is present. Per HTTP semantics, a content-type header is only meaningful when a message body is present (RFC 9110 §8.3).
The server should process the request normally and return the appropriate response:
404(TaskNotFoundError) for a non-existent task409(TaskNotCancelableError) for a task in a terminal state
Actual behavior
The server returns 415 Unsupported Media Type before evaluating the request:
{"title":"Incompatible content types","details":"","status":415,"type":"https://a2a-protocol.org/errors/content-type-not-supported"}Reproducer
# Without Content-Type → 415 (incorrect)
curl -s -X POST http://localhost:9999/tasks/nonexistent:cancel
# {"title":"Incompatible content types","details":"","status":415,"type":"https://a2a-protocol.org/errors/content-type-not-supported"}
# With Content-Type → 404 (correct)
curl -s -X POST http://localhost:9999/tasks/nonexistent:cancel \
-H "Content-Type: application/json"
# {"title":"Task not found","details":"","status":404,"type":"https://a2a-protocol.org/errors/task-not-found"}TCK test
tests/compatibility/core_operations/test_task_lifecycle.py::TestCancelTask::test_cancel_task_returns_updated_state[http_json]
tests/compatibility/core_operations/test_requirements.py::test_must_requirement[CORE-CANCEL-003-http_json]
tests/compatibility/http_json/test_http_status.py::TestHttpJsonStatusCodes::test_task_not_found_returns_404
tests/compatibility/http_json/test_http_status.py::TestHttpJsonStatusCodes::test_task_not_cancelable_returns_409
Relevant log output
Code of Conduct
- I agree to follow this project's Code of Conduct