dinoDayo opened a new issue, #63209:
URL: https://github.com/apache/airflow/issues/63209

   ### Apache Airflow version
   
   Other Airflow 3 version (please specify below)
   
   ### If "Other Airflow 3 version" selected, which one?
   
   3.0.6
   
   ### What happened?
   
   When triggering a DAG, the task subprocess is immediately killed with 
SIGKILL. The api-server logs show a **422 UnprocessableEntity** on `PATCH 
/execution/task-instances/{id}/run`. The task never reaches RUNNING state.      
                           
                                                                                
                                                
   API server log:                                                              
                                              
   `INFO: "PATCH /execution/task-instances/{id}/run HTTP/1.1" 422 Unprocessable 
Entity`                                        
                                                                                
                                                
   The 422 response body contains a Pydantic `model_attributes_type` validation 
error, indicating the request body was received 
   as a plain string rather than a parsed dict.
   
   In `apache-airflow-task-sdk==1.0.6`, `airflow/sdk/api/client.py` sends 
requests to the execution API using httpx's content=parameter:                  
                                                                                
               
   ```              
   resp = self.client.patch(f"task-instances/{id}/run", 
content=body.model_dump_json())                                       
   ```                                       
    
   Using `content=` sets the raw request body but does not set the Content-Type 
header. Without `Content-Type: application/json`, cadwyn/FastAPI cannot 
JSON-parse the body and passes it to Pydantic as a raw string, causing a 
model_attributes_type validation error and returning 422.                       
                                                                 
   `supervisor.py:_on_child_started` calls `client.task_instances.start()` and 
treats any non-2xx response as fatal, immediately sending **SIGKILL** to the 
task subprocess.                                                                
                    
   
   This affects all endpoints in client.py that use 
`content=body.model_dump_json()` (heartbeat, state updates, etc.).
   
   ### What you think should happen instead?
   
   The requests should succeed and the task should reach RUNNING state.
   
   **The Fix** (worked locally for me)                                          
                                                                                
                                         
   Adding `headers={"Content-Type": "application/json"}` to all 
`content=body.model_dump_json()` call sites in client.py resolves the issue:
   ```                                                                          
                                          
   resp = self.client.patch( 
       f"task-instances/{id}/run",                                              
                                              
       content=body.model_dump_json(),
       headers={"Content-Type": "application/json"},                            
                                              
   )                                           
   ```                                          
   Alternatively, use `json=body.model_dump()` which sets the header 
automatically.                                                                  
                    
   
   **Relationship to existing fixes**                                           
                                              
   This bug was addressed in the 3.1.x branch in two stages:                    
                                                                                
    
     - PR #57377 (merged Oct 2025, shipped in 3.1.1) — first fix attempt, added 
Content-Type header to Task SDK calls.
     - PR #59676 (merged Dec 2025, shipped in 3.1.6) — corrected a logic bug in 
#57377 where content=None and headers=None were 
     passed as kwargs, causing the header to not actually be applied.
   
   Neither fix has been backported to 3.0.x. This is a blocking issue for users 
of AWS MWAA, which currently supports Airflow 3.0.6 as its latest 3.x version 
and has no upgrade path to 3.1.x. A backport of PR #59676 to the 3.0.x branch 
would resolve this.
   
   ### How to reproduce
   
   1. Run Airflow 3.0.6 locally with LocalExecutor
   2. Trigger any DAG                                                           
                                              
   3. Observe 422 on PATCH /execution/task-instances/{id}/run in api-server logs
   4. Task immediately transitions to FAILED state    
   
   ### Operating System
   
   macOS / Docker (also expected to affect any deployment running task-sdk 
1.0.6)     
   
   ### Versions of Apache Airflow Providers
   
   `apache-airflow-task-sdk==1.0.6`
   
   ### Deployment
   
   Docker-Compose
   
   ### Deployment details
   
   I define the patch in a python file, import it into my Dockerfile, and run 
it during the build phase.
   
   ### Anything else?
   
   _No response_
   
   ### Are you willing to submit PR?
   
   - [ ] Yes I am willing to submit a PR!
   
   ### Code of Conduct
   
   - [x] I agree to follow this project's [Code of 
Conduct](https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to