# upstream sent invalid header: "X_Custom_Header: value" while reading response header from upstream, client: 10.0.0.1, server: example.com

- **ID:** `nginx/upstream-sent-invalid-header-underscore`
- **Domain:** nginx
- **Category:** protocol_error
- **Verification:** ai_generated
- **Fix Rate:** 95%

## Root Cause

Nginx by default discards HTTP headers containing underscores in the name, treating them as invalid per RFC 7230 due to potential inconsistencies with CGI/legacy systems.

## Version Compatibility

| Version | Status | Introduced | Deprecated |
|---------|--------|------------|------------|
| nginx/1.18.0 | active | — | — |
| nginx/1.20.0 | active | — | — |
| nginx/1.24.0 | active | — | — |
| nginx/1.26.0 | active | — | — |

## Workarounds

1. **Enable underscores_in_headers in the http, server, or location block: `underscores_in_headers on;`** (95% success)
   ```
   Enable underscores_in_headers in the http, server, or location block: `underscores_in_headers on;`
   ```
2. **If security is a concern, rename the header in the upstream application to use hyphens (e.g., X-Custom-Header instead of X_Custom_Header) and update all clients.** (80% success)
   ```
   If security is a concern, rename the header in the upstream application to use hyphens (e.g., X-Custom-Header instead of X_Custom_Header) and update all clients.
   ```
3. **Use proxy_set_header to map the incoming header to a sanitized version: `proxy_set_header X-Custom-Header $http_x_custom_header;` (requires underscores_in_headers on or header name change).** (85% success)
   ```
   Use proxy_set_header to map the incoming header to a sanitized version: `proxy_set_header X-Custom-Header $http_x_custom_header;` (requires underscores_in_headers on or header name change).
   ```

## Dead Ends

- **** — While this works, it requires application changes that may not be feasible in all deployments; nginx can be configured to accept underscores. (40% fail)
- **** — ignore_invalid_headers controls general header validity, but underscore handling is controlled by the underscores_in_headers directive specifically. (70% fail)
- **** — The default behavior is intentional and unchanged across versions; a config change is required. (90% fail)
