Skip to content

[Bug]: HTTP+JSON transport returns 415 on POST requests without Content-Type header #747

@jmesnil

Description

@jmesnil

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

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 task
  • 409 (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

Metadata

Metadata

Assignees

Labels

compatibilityIssue related to A2A compatibilityhttp+jsonIssue related to the HTTP+JSON transport

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions