Java
Spring Boot
Request Headers
Null Value
Web Development

Spring Boot request header return null value

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

When @RequestHeader returns null in Spring Boot, the header either was not sent by the client, was misspelled, or was stripped by a proxy or load balancer before reaching your application. Spring is case-insensitive for header names, so the issue is almost always about the header being absent rather than a casing mismatch. The fix depends on which scenario applies: make the header optional with required = false, check your client request, or inspect your reverse proxy configuration.

How @RequestHeader Works

java
1@RestController
2public class MyController {
3
4    @GetMapping("/api/data")
5    public String getData(@RequestHeader("X-Custom-Token") String token) {
6        return "Token: " + token;
7    }
8}

If the X-Custom-Token header is missing from the request, Spring throws MissingRequestHeaderException (400 Bad Request) by default — not null. You only get null when you explicitly make the header optional.

Cause 1: Header Not Sent by Client

The most common cause. Verify the header is actually being sent:

bash
1# Test with curl — include the header explicitly
2curl -H "X-Custom-Token: abc123" http://localhost:8080/api/data
3
4# Without the header — triggers 400 error
5curl http://localhost:8080/api/data

In JavaScript fetch calls, headers are often missing due to typos:

javascript
1// WRONG — header name typo
2fetch('/api/data', {
3    headers: { 'X-Custm-Token': 'abc123' }  // missing 'o'
4});
5
6// CORRECT
7fetch('/api/data', {
8    headers: { 'X-Custom-Token': 'abc123' }
9});

Cause 2: Header Made Optional Without Default

java
1// This returns null when the header is missing
2@GetMapping("/api/data")
3public String getData(
4        @RequestHeader(value = "X-Custom-Token", required = false) String token) {
5    // token is null if header is absent
6    return "Token: " + token;  // "Token: null"
7}
8
9// Fix: provide a default value
10@GetMapping("/api/data")
11public String getData(
12        @RequestHeader(value = "X-Custom-Token", defaultValue = "none") String token) {
13    return "Token: " + token;  // "Token: none" when absent
14}

Cause 3: Proxy or Load Balancer Stripping Headers

Reverse proxies (Nginx, Apache, AWS ALB) can strip or rename custom headers:

nginx
1# Nginx — custom headers with underscores are dropped by default
2# Fix: enable underscores in headers
3server {
4    underscores_in_headers on;
5
6    location / {
7        proxy_pass http://localhost:8080;
8        proxy_set_header X-Custom-Token $http_x_custom_token;
9    }
10}

AWS Application Load Balancer strips headers with underscores by default. Use hyphens instead: X-Custom-Token instead of X_Custom_Token.

Cause 4: CORS Preflight Dropping Headers

Browser CORS preflight requests (OPTIONS) do not include custom headers. If your controller handles OPTIONS requests, the header will be absent:

java
1@Configuration
2public class CorsConfig implements WebMvcConfigurer {
3    @Override
4    public void addCorsMappings(CorsRegistry registry) {
5        registry.addMapping("/api/**")
6                .allowedOrigins("http://localhost:3000")
7                .allowedHeaders("X-Custom-Token", "Content-Type")
8                .allowedMethods("GET", "POST", "PUT", "DELETE");
9    }
10}

The allowedHeaders configuration must include your custom header name, or the browser will not send it in the actual request.

Cause 5: Using HttpServletRequest Directly

java
1@GetMapping("/api/data")
2public String getData(HttpServletRequest request) {
3    // getHeader() returns null if header is absent — no exception
4    String token = request.getHeader("X-Custom-Token");
5
6    if (token == null) {
7        return "Header not found";
8    }
9    return "Token: " + token;
10}

HttpServletRequest.getHeader() always returns null for missing headers without throwing an exception, unlike @RequestHeader with required = true.

Debugging Headers

java
1@GetMapping("/api/debug")
2public Map<String, String> debugHeaders(HttpServletRequest request) {
3    Map<String, String> headers = new HashMap<>();
4    Enumeration<String> headerNames = request.getHeaderNames();
5    while (headerNames.hasMoreElements()) {
6        String name = headerNames.nextElement();
7        headers.put(name, request.getHeader(name));
8    }
9    return headers;  // Returns all headers as JSON
10}

Call this endpoint to see exactly which headers arrive at your application.

Using Optional for Nullable Headers

java
1@GetMapping("/api/data")
2public String getData(
3        @RequestHeader(value = "X-Custom-Token", required = false)
4        Optional<String> token) {
5    return token.map(t -> "Token: " + t)
6                .orElse("No token provided");
7}

Common Pitfalls

  • Assuming null means the annotation failed: @RequestHeader with required = true (default) throws a 400 error, not null. If you see null, you made the header optional somewhere.
  • Underscore in header names: Nginx drops headers with underscores (X_Custom_Token) by default. Use hyphens (X-Custom-Token) or enable underscores_in_headers on.
  • Testing with browser DevTools: The browser may not send custom headers on GET requests unless you use fetch() or XMLHttpRequest. Direct URL bar navigation sends no custom headers.
  • Case sensitivity confusion: HTTP header names are case-insensitive per the spec, and Spring handles this correctly. x-custom-token and X-Custom-Token are the same header.
  • Spring Security intercepting requests: If Spring Security is configured, it may reject requests before they reach your controller. Check your security filter chain if headers seem to disappear.

Summary

  • @RequestHeader throws 400 by default for missing headers — use required = false to get null instead
  • Always verify the client is actually sending the header (use curl or browser DevTools)
  • Reverse proxies often strip custom headers with underscores — use hyphens
  • Add allowedHeaders in CORS configuration for custom headers from browsers
  • Use HttpServletRequest.getHeader() or Optional<String> for graceful null handling
  • Create a debug endpoint to inspect all incoming headers when troubleshooting

Related reading
Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.