Bug ID: CONTEXTFORGE-006 Component: ContextForge MCP Gateway Affected Version: v0.8.0, v1.0.0-BETA-1, v1.0.0-BETA-2 Severity: Informational (not a bug) Status: BY DESIGN (FastAPI standard behavior) Reported: 2025-11-09 Last Validated: 2026-02-06
The POST /teams endpoint returns HTTP 422 (Unprocessable Entity) for request validation errors (like missing required fields) instead of the more standard HTTP 400 (Bad Request). While both status codes indicate client errors, 422 is semantically meant for well-formed requests with semantic errors, whereas 400 is more appropriate for malformed requests or missing required fields.
POST /teams
When creating a team without a required field (e.g., name):
- The API should return HTTP 400 Bad Request
- The response should include error details about the missing field
- This matches HTTP semantics where 400 = malformed request
Example:
POST /teams
{
"description": "A team without a name"
}
Response: 400 Bad Request
{
"detail": "name field is required"
}When creating a team without a required field:
- The API returns HTTP 422 Unprocessable Entity
- The response includes validation error details (FastAPI/Pydantic default)
- The SDK's error handling doesn't capture the Response object correctly
Example:
POST /teams
{
"description": "A team without a name"
}
Response: 422 Unprocessable Entity
{
"detail": [
{
"type": "missing",
"loc": ["body", "name"],
"msg": "Field required",
"input": {...}
}
]
}-
Create a team without the required
namefield:curl -X POST http://localhost:8000/teams/ \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"description": "No name provided"}'
-
Observe response status code is 422, not 400
-
SDK test expects 400:
_, resp, err := client.Teams.Create(ctx, team) if resp.StatusCode != http.StatusBadRequest { // Expects 400 t.Errorf("Expected 400, got %d", resp.StatusCode) // Gets 422 }
SDK integration test shows the mismatch:
=== RUN TestTeamsService_ErrorHandling/create_team_without_required_name_returns_400
teams_integration_test.go:511: Expected status 400, got &{0x140003dc2d0 {0 0 0001-01-01 00:00:00 +0000 UTC}}
The Response object shows StatusCode of 0, which indicates the SDK's error handling might not be parsing 422 responses into the Response object correctly.
Location: FastAPI/Pydantic validation in mcpgateway/routers/teams.py
FastAPI automatically validates request bodies against Pydantic models and returns 422 Unprocessable Entity for validation errors by default. This is FastAPI's standard behavior:
@teams_router.post("/", response_model=TeamResponse)
async def create_team(request: TeamCreateRequest, ...):
# If TeamCreateRequest validation fails (missing required fields),
# FastAPI returns 422 automatically before this function is called
...Pydantic Model:
class TeamCreateRequest(BaseModel):
name: str # Required field
description: Optional[str] = None
...When name is missing, Pydantic validation fails and FastAPI returns 422 with detailed validation error information.
The SDK's Do() method in contextforge.go may not be properly populating the Response object for 422 errors. The test output shows StatusCode: 0 which suggests the Response might be nil or not fully constructed.
Location: contextforge/contextforge.go - Do() method
The SDK needs to ensure that even for validation errors (422), the Response object is properly constructed with the status code.
422 Unprocessable Entity (RFC 4918):
- Originally defined for WebDAV
- Means the request was well-formed but contains semantic errors
- FastAPI uses this for Pydantic validation failures
- Example: All fields present but value constraints violated
400 Bad Request (RFC 7231):
- General client error for malformed requests
- More appropriate for missing required fields
- Indicates the request itself is invalid
- Example: Missing required fields, invalid JSON syntax
For missing required fields, 400 is more semantically correct than 422.
Need to verify if other ContextForge endpoints use the same pattern:
- Do Tools, Resources, Servers, Prompts, Agents also return 422?
- Is this a consistent API-wide pattern?
- If consistent, should SDK accept both 400 and 422?
Severity: Low
- ❌ API uses less common 422 status code
- ❌ Test expectations don't match actual behavior
- ❌ SDK Response object may not be populated correctly for 422
- ✅ Error is still properly returned (validation works)
- ✅ Error details are provided in response
- ✅ Workaround exists (check for 422 or any 4xx error)
Affected Users:
- SDK users expecting standard HTTP 400 for validation errors
- Automated tests checking specific status codes
- API consumers following strict HTTP semantics
Business Impact: Minimal - The error is still returned and caught, just with a different status code than expected.
Option 1: Accept Both 400 and 422
Update SDK tests to accept either status code:
if resp.StatusCode != http.StatusBadRequest &&
resp.StatusCode != http.StatusUnprocessableEntity {
t.Errorf("Expected 400 or 422, got %d", resp.StatusCode)
}Option 2: Just Check for Error
Don't verify specific status codes for validation errors:
if err == nil {
t.Error("Expected error when creating team without name")
}
// Don't check specific status codeOption 3: Check for Any 4xx Error
if resp.StatusCode < 400 || resp.StatusCode >= 500 {
t.Errorf("Expected 4xx error, got %d", resp.StatusCode)
}Override FastAPI's default to return 400 for validation errors:
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
return JSONResponse(
status_code=400, # Instead of 422
content={"detail": exc.errors()},
)This makes the API more consistent with HTTP semantics.
If 422 is intentional, document it clearly in the API specification:
/teams:
post:
responses:
201:
description: Team created successfully
422: # Not 400
description: Validation error (missing required fields)And update SDK tests to expect 422.
Ensure the SDK properly constructs Response objects for 422 errors:
// In Do() method
resp := newResponse(httpResp)
if httpResp.StatusCode == 422 {
// Ensure Response object is populated
// Parse validation error details
}Status:
The SDK correctly returns errors for validation failures, but the Response object appears to have StatusCode = 0 for 422 responses. This should be investigated and fixed.
Required SDK Changes:
- Verify Response object is populated for 422 status codes
- Update tests to accept 422 for validation errors (or wait for API fix)
- Document that validation errors return 422, not 400
- Should check if this affects other resources (Tools, Servers, etc.)
- May be related to how FastAPI is configured globally
- SDK Response construction may have issues with non-standard status codes
- FastAPI Documentation: https://fastapi.tiangolo.com/tutorial/handling-errors/
- RFC 4918 (422): https://tools.ietf.org/html/rfc4918#section-11.2
- RFC 7231 (400): https://tools.ietf.org/html/rfc7231#section-6.5.1
- SDK Integration Test:
test/integration/teams_integration_test.go:499-515 - SDK Do Method:
contextforge/contextforge.go
- Verify if 422 is used consistently across all ContextForge endpoints
- Decide if API should be changed to return 400 (recommended)
- Fix SDK Response construction for 422 status codes
- Update SDK tests based on final decision
- Document the expected behavior clearly
Validated: 2026-01-13
This behavior is BY DESIGN - FastAPI/Pydantic's standard behavior for validation errors.
ContextForge uses FastAPI with Pydantic for request validation. FastAPI's default behavior is to return HTTP 422 for Pydantic validation errors. This is:
- Standard FastAPI behavior - Not a bug or oversight
- Documented behavior - FastAPI documentation clearly states this
- Consistent across the API - All endpoints using Pydantic validation return 422
Update SDK test expectations to accept 422 for validation errors rather than treating this as a bug. This is the correct approach because:
- 422 is a valid HTTP status code for "semantically invalid" requests
- FastAPI uses this consistently
- Changing the API to return 400 would break other clients expecting 422
- The error details are provided correctly in the response body
Update integration tests to expect 422 instead of 400 for Pydantic validation errors:
// Change from:
if apiErr.Response.StatusCode != http.StatusBadRequest { // 400
t.Errorf("Expected 400, got %d", apiErr.Response.StatusCode)
}
// To:
if apiErr.Response.StatusCode != http.StatusUnprocessableEntity { // 422
t.Errorf("Expected 422, got %d", apiErr.Response.StatusCode)
}Report Generated: 2025-11-09 Tested Against: ContextForge v0.8.0 Validated Against: ContextForge v1.0.0-BETA-2 Reporter: go-contextforge SDK Team
Validated: 2026-02-06
- Still Valid? N/A. This remains an informational note, not a defect.
- Is it actually a bug? No.
422for schema validation is standard FastAPI behavior.
- Current app still uses FastAPI/Pydantic default validation pipeline.
- Validation failures continue to return structured
422responses consistently.