@@ -847,6 +847,62 @@ def test_send_task_wrapped(
847847 assert span ["trace_id" ] == kwargs ["headers" ]["sentry-trace" ].split ("-" )[0 ]
848848
849849
850+ def test_user_custom_headers_accessible_in_task (init_celery ):
851+ """
852+ Regression test for https://github.com/getsentry/sentry-python/issues/5566
853+
854+ User-provided custom headers passed to apply_async() must be accessible
855+ via task.request.headers on the worker side.
856+ """
857+ celery = init_celery (traces_sample_rate = 1.0 )
858+
859+ @celery .task (name = "custom_headers_task" , bind = True )
860+ def custom_headers_task (self ):
861+ return dict (self .request .headers or {})
862+
863+ custom_headers = {
864+ "my_custom_key" : "my_value" ,
865+ "correlation_id" : "abc-123" ,
866+ "tenant_id" : "tenant-42" ,
867+ }
868+
869+ with start_transaction (name = "test" ):
870+ result = custom_headers_task .apply_async (headers = custom_headers )
871+
872+ received_headers = result .get ()
873+ for key , value in custom_headers .items ():
874+ assert received_headers .get (key ) == value , (
875+ f"Custom header { key !r} not found in task.request.headers"
876+ )
877+
878+
879+ def test_user_custom_headers_do_not_overwrite_sentry_headers (init_celery ):
880+ """
881+ If a user passes a header with a key that collides with a Sentry header,
882+ the Sentry-generated value must take precedence.
883+ """
884+ celery = init_celery (traces_sample_rate = 1.0 )
885+
886+ @celery .task (name = "headers_precedence_task" , bind = True )
887+ def headers_precedence_task (self ):
888+ return dict (self .request .headers or {})
889+
890+ with start_transaction (name = "test" ):
891+ result = headers_precedence_task .apply_async (
892+ headers = {
893+ "sentry-trace" : "user-supplied-value" ,
894+ "my_custom_key" : "my_value" ,
895+ },
896+ )
897+
898+ received_headers = result .get ()
899+ # Sentry's own sentry-trace must NOT be the user-supplied value
900+ assert received_headers .get ("sentry-trace" ) != "user-supplied-value"
901+ assert "sentry-trace" in received_headers
902+ # User custom header is still preserved
903+ assert received_headers .get ("my_custom_key" ) == "my_value"
904+
905+
850906@pytest .mark .skip (reason = "placeholder so that forked test does not come last" )
851907def test_placeholder ():
852908 """Forked tests must not come last in the module.
0 commit comments