Pika Python
RabbitMQ
Message Queuing
Programming
BasicProperties Header

how to get basicproperties header field in pika python from rabbitmq messages?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Pika consumers, the properties argument is already the AMQP BasicProperties object for the message you received. If you want custom header values, the field you usually want is properties.headers, not a separate "header object."

Where the Headers Live

A RabbitMQ delivery callback in Pika normally looks like this:

python
def callback(ch, method, properties, body):
    ...

The important parameters are:

  • 'method: delivery metadata such as routing key and delivery tag'
  • 'properties: AMQP message properties'
  • 'body: the payload bytes'

Custom headers are stored inside properties.headers, which is usually a Python dictionary or None if no headers were set.

Reading BasicProperties Safely

The simplest safe pattern is:

python
1import pika
2
3def callback(ch, method, properties, body):
4    headers = properties.headers or {}
5    trace_id = headers.get("trace_id")
6    tenant = headers.get("tenant")
7
8    print("body:", body.decode("utf-8"))
9    print("content_type:", properties.content_type)
10    print("delivery_mode:", properties.delivery_mode)
11    print("trace_id:", trace_id)
12    print("tenant:", tenant)
13
14connection = pika.BlockingConnection(pika.ConnectionParameters("localhost"))
15channel = connection.channel()
16channel.queue_declare(queue="demo")
17channel.basic_consume(queue="demo", on_message_callback=callback, auto_ack=True)
18channel.start_consuming()

That properties.headers or {} part matters. If the publisher did not send headers, properties.headers may be None.

Publishing a Message With Headers

To read headers, you first need to publish them. In Pika, you attach them when building BasicProperties.

python
1import pika
2
3connection = pika.BlockingConnection(pika.ConnectionParameters("localhost"))
4channel = connection.channel()
5channel.queue_declare(queue="demo")
6
7channel.basic_publish(
8    exchange="",
9    routing_key="demo",
10    body="hello",
11    properties=pika.BasicProperties(
12        content_type="text/plain",
13        delivery_mode=2,
14        headers={
15            "trace_id": "req-123",
16            "tenant": "acme",
17            "retry_count": 0,
18        },
19    ),
20)
21
22connection.close()

On the consumer side, those values show up under properties.headers.

Accessing One Header Field

If you only need one header, read it directly from the dictionary.

python
1def callback(ch, method, properties, body):
2    headers = properties.headers or {}
3    request_id = headers.get("request_id")
4
5    if request_id is None:
6        print("request_id header was not provided")
7    else:
8        print("request_id =", request_id)

Use get instead of direct indexing unless the header is mandatory. Direct indexing raises KeyError when the field is missing.

headers Versus Other Message Properties

Do not confuse headers with the built-in AMQP properties already available as top-level attributes.

Examples of built-in properties include:

  • 'properties.correlation_id'
  • 'properties.reply_to'
  • 'properties.message_id'
  • 'properties.timestamp'
  • 'properties.content_type'

Those are not stored inside properties.headers. If a producer sets correlation_id, read it from properties.correlation_id, not properties.headers["correlation_id"].

A Practical Consumer Example

The example below prints both built-in properties and custom headers so you can see the distinction clearly.

python
1import pika
2
3def callback(ch, method, properties, body):
4    headers = properties.headers or {}
5
6    print("routing_key:", method.routing_key)
7    print("message_id:", properties.message_id)
8    print("correlation_id:", properties.correlation_id)
9    print("all headers:", headers)
10
11    retry_count = headers.get("retry_count", 0)
12    print("retry_count:", retry_count)
13
14    ch.basic_ack(delivery_tag=method.delivery_tag)
15
16connection = pika.BlockingConnection(pika.ConnectionParameters("localhost"))
17channel = connection.channel()
18channel.queue_declare(queue="demo")
19channel.basic_consume(queue="demo", on_message_callback=callback, auto_ack=False)
20channel.start_consuming()

This is the version you usually want in real code, because it acknowledges the message only after processing.

Header Types and Serialization

RabbitMQ headers are AMQP field-table values. In practice, keep them simple:

  • strings
  • integers
  • booleans
  • small structured values you know your consumers can parse

If you need rich nested data, putting JSON in the message body is often cleaner than pushing too much structure into headers.

Headers are best for metadata such as:

  • trace IDs
  • tenant IDs
  • version flags
  • retry counters
  • feature switches

Common Pitfalls

  • Looking for headers on method instead of properties.
  • Assuming properties.headers is always a dictionary; it may be None.
  • Storing built-in properties such as correlation_id inside custom headers and then forgetting where to read them.
  • Using direct dictionary indexing for optional headers and crashing on missing values.
  • Putting large business payloads into headers instead of the body.

Summary

  • In Pika consumers, the properties callback argument is the BasicProperties object.
  • Custom header values are available under properties.headers.
  • Use properties.headers or {} to handle messages with no headers safely.
  • Read built-in AMQP properties from their dedicated attributes, not from the headers dictionary.
  • Keep headers small and use the message body for real payload data.

Course illustration
Course illustration

All Rights Reserved.