Airflow 3 update_xcom_entry is adding unnecessary quotes to the string value
- Dominant language
- Python
- Stars
- 46.9k
- Forks
- 17.8k
- Avg merge
- 2d 9h
- Merged PRs (30d)
- 472
Description
### Apache Airflow version
3.1.8
### What happened and how to reproduce it?
I am using apache-airflow-client==3.1.6 to get/create/update XCOM value. What I see is that
- `create_xcom_entry` works correctly, if a pass a string value, it properly stores that, and `get_xcom_entry` gets back the exact same value.
- `update_xcom_entry` though quotes to the value, so `get_xcom_entry` gets back the value in quotation marks. I see the same on the UI (Browse/XComs)
Code to reproduce the issue:
```python
def reporduce_the_issue():
api_client_provider = AirflowApiClientProvider()
DAG_ID = '_for_testing'
DAG_RUN_ID = 'manual__2026-03-31T12:59:12.433086+00:00'
TASK_ID = 'task1'
XCOM_KEY = random_xcom_key()
XCOM_VALUE1 = 'test_value1'
XCOM_VALUE2 = 'test_value2'
with api_client_provider.get_api_client() as api_client:
xcom_api = airflow_client.client.XComApi(api_client)
log.info('Check that it does not exist yet.')
try:
xcom_api.get_xcom_entry(
dag_id=DAG_ID,
dag_run_id=DAG_RUN_ID,
task_id=TASK_ID,
xcom_key=XCOM_KEY,
)
log.error(f'Random is not random enough, try it again')
return
except NotFoundException:
pass
log.info(f'Create {XCOM_KEY} with value {XCOM_VALUE1}.')
xcom_api.create_xcom_entry(
dag_id=DAG_ID,
dag_run_id=DAG_RUN_ID,
task_id=TASK_ID,
x_com_create_body=XComCreateBody(key=XCOM_KEY, value=XCOM_VALUE1)
)
log.info('Get the value.')
xcom_entry = xcom_api.get_xcom_entry(
dag_id=DAG_ID,
dag_run_id=DAG_RUN_ID,
task_id=TASK_ID,
xcom_key=XCOM_KEY,
)
val = xcom_entry.to_dict().get('value')
log.info(f'Value after creation: {val=}')
log.info(f'Update {XCOM_KEY} with value {XCOM_VALUE2}.')
xcom_api.update_xcom_entry(
dag_id=DAG_ID,
dag_run_id=DAG_RUN_ID,
task_id=TASK_ID,
xcom_key=XCOM_KEY,
x_com_update_body=XComUpdateBody(value=XCOM_VALUE2)
)
log.info('Get the value.')
xcom_entry = xcom_api.get_xcom_entry(
dag_id=DAG_ID,
dag_run_id=DAG_RUN_ID,
task_id=TASK_ID,
xcom_key=XCOM_KEY,
)
val = xcom_entry.to_dict().get('value')
log.info(f'Value after update: {val=}')
```
### What you think should happen instead?
The value should not be changed by the update method. It should not be quoted.
```
2026-04-01 11:43:24,459 - __main__ - INFO - Check that it does not exist yet.
2026-04-01 11:43:24,513 - __main__ - INFO - Create task_ikp517fwfb with value test_value1.
2026-04-01 11:43:24,561 - __main__ - INFO - Get the value.
2026-04-01 11:43:24,590 - __main__ - INFO - Value after creation: val='"test_value1"'
2026-04-01 11:43:24,590 - __main__ - INFO - Update task_ikp517fwfb with value test_value2.
2026-04-01 11:43:24,624 - __main__ - INFO - Get the value.
2026-04-01 11:43:24,652 - __main__ - INFO - Value after update: val='"\\"test_value2\\""'
```
### Operating System
Debian GNU/Linux 12 (bookworm)
### Versions of Apache Airflow Providers
apache-airflow==3.1.8
apache-airflow-client==3.1.6
apache-airflow-core==3.1.8
### Deployment
Docker-Compose
### Deployment details
_No response_
### Anything else?
_No response_
### Are you willing to submit PR?
- [x] 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)
Contributor guide
Assessment
This issue has not been assessed yet.