-
Notifications
You must be signed in to change notification settings - Fork 133
Description
What happened?
Summary
CreateTaskPushNotificationConfig on HTTP+JSON returns 422 because the SUT requires taskId in the request body instead of extracting it from the URL path /tasks/{id}/pushNotificationConfigs. Per the proto's body: "*" HTTP transcoding rule, fields bound to URL path variables (like task_id) are extracted from the path, and only the remaining fields belong in the request body.
Requirement
- ID: PUSH-CREATE-001
- Section: 3.1.7 — CreatePushNotificationConfig establishes webhook endpoint
- Level: MUST
- Spec: specification.md#317-create-push-notification-config
Specification
The CreatePushNotificationConfig operation MUST establish a webhook endpoint for task update notifications. When task updates occur, the agent will send HTTP POST requests to the configured webhook URL with
StreamResponsepayloads. The configuration MUST persist until task completion or explicit deletion.
The HTTP+JSON binding for this operation is defined as:
| Operation | HTTP+JSON |
|---|---|
| Create push notification config | POST /tasks/{id}/pushNotificationConfigs |
The proto definition uses body: "*" with task_id in the URL path, meaning task_id is extracted from the path, and only the remaining fields belong in the request body.
Expected behavior
A POST /tasks/{task_id}/pushNotificationConfigs request with the push notification config in the body (without taskId) should succeed and return the created configuration:
POST /tasks/914b1064-.../pushNotificationConfigs
Content-Type: application/json
{"id": "my-config-001", "url": "https://example.com/webhook"}
Response: 201 Created with the TaskPushNotificationConfig.
Actual behavior
The SUT returns 422 with error "taskId is required", indicating it expects taskId in the request body rather than extracting it from the URL path:
{"error": "io.a2a.spec.InvalidParamsError", "message": "taskId is required"}When taskId is redundantly included in the body, the request succeeds (201), confirming the SUT does not extract the task ID from the URL path segment.
Note: This same operation works correctly on JSON-RPC and gRPC transports, where taskId is naturally part of the request parameters/message. The failure is isolated to HTTP+JSON.
Reproducer
# Step 1: Create a task via SendMessage
TASK_ID=$(curl -s -X POST http://localhost:9999/message:send \
-H "Content-Type: application/json" \
-d '{
"message": {
"role": "ROLE_USER",
"parts": [{"text": "hello"}],
"messageId": "msg-001"
},
"configuration": {
"acceptedOutputModes": ["text"]
}
}' | python3 -c "import sys,json; print(json.load(sys.stdin)['task']['id'])")
echo "Task ID: $TASK_ID"
# Step 2: Create push notification config (FAILS with 422)
# Per spec, task_id comes from the URL path; body contains only the config fields
curl -s -w "\nHTTP %{http_code}" \
-X POST "http://localhost:9999/tasks/${TASK_ID}/pushNotificationConfigs" \
-H "Content-Type: application/json" \
-d '{"id": "my-push-config", "url": "https://example.com/webhook"}'
# Expected: 201 with TaskPushNotificationConfig
# Actual: 422 {"error":"io.a2a.spec.InvalidParamsError","message":"taskId is required"}
# Step 3: With taskId in body (SUCCEEDS — confirms the bug)
curl -s -w "\nHTTP %{http_code}" \
-X POST "http://localhost:9999/tasks/${TASK_ID}/pushNotificationConfigs" \
-H "Content-Type: application/json" \
-d "{\"taskId\": \"${TASK_ID}\", \"id\": \"my-push-config\", \"url\": \"https://example.com/webhook\"}"
# Returns: 201 (should work without taskId in body)TCK tests
tests/compatibility/core_operations/test_push_notifications.py::TestPushNotificationCrud::test_create_push_config[grpc]
tests/compatibility/core_operations/test_push_notifications.py::TestPushNotificationCrud::test_create_push_config[http_json]
tests/compatibility/core_operations/test_push_notifications.py::TestPushNotificationCrud::test_create_push_config[jsonrpc]
Relevant log output
Code of Conduct
- I agree to follow this project's Code of Conduct