Skip to content
🎉 Launch sale:50% off everything over $22 — automatically applied at checkout· ends Aug 2Shop the sale →
DevOps AI ToolKit
Newsletter
All guides
AI for NGINX By James Joyner IV · · 8 min read Last reviewed Jul 2026

NGINX Error Guide: 'unexpected end of file, expecting }' — Fix Unbalanced Braces

Quick answer

Fix 'unexpected end of file, expecting }' in NGINX: find the unclosed block or stray brace across included files and balance your { } pairs.

  • #nginx
  • #web-server
  • #troubleshooting
  • #errors
Free toolkit

Stuck on this NGINX error? Get the free incident triage checklist

A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.

Overview

NGINX prints this during config parsing when it reaches the end of a file while still inside an open block — an unbalanced { }. The message points at the file where parsing ran out, usually with a line number at or near the end:

nginx: [emerg] unexpected end of file, expecting "}" in /etc/nginx/nginx.conf:98

The reported line is where NGINX ran out of input, not necessarily where the mistake is. The actual unclosed block might be dozens of lines earlier — or in a completely different file pulled in via include. NGINX concatenates included files as it parses, so a missing brace in one snippet can surface as an “end of file” error in another.

Symptoms

  • nginx -t fails with [emerg] unexpected end of file, expecting "}" and a file/line near the end of a file.
  • Reloads fail; the previously loaded config keeps running (old workers persist).
  • The reported line looks fine — it’s the closing brace of the whole file, but a block opened earlier was never closed.
  • It appeared right after adding a new location, if, map, or upstream block, or a new included file.

Common Root Causes

  • A block opened but never closed — a location, server, http, map, upstream, or if with a { and no matching }.
  • An extra or missing brace in an included file — the imbalance lives in conf.d/*.conf or a sites-enabled snippet, but the error is reported in nginx.conf.
  • A brace inside a string that isn’t quoted — a { in a log_format or add_header value that NGINX reads as a block opener.
  • Copy-paste of a partial block — pasting a location { ... without its closing brace.
  • Commented-out closing brace — a # accidentally placed before a } that was needed.

Diagnostic Workflow

The fastest way to localize an imbalance is a brace count per file. Any file where opens and closes don’t match is the suspect:

# Count { and } in every config file; mismatched counts flag the culprit
for f in /etc/nginx/nginx.conf /etc/nginx/conf.d/*.conf /etc/nginx/sites-enabled/*; do
  [ -f "$f" ] || continue
  o=$(grep -o '{' "$f" | wc -l); c=$(grep -o '}' "$f" | wc -l)
  [ "$o" != "$c" ] && echo "IMBALANCE: $f  open=$o close=$c"
done

Let nginx -t confirm and, importantly, dump the effective merged config so you can see block nesting across includes:

nginx -t
nginx -T | less    # full assembled config with all includes inlined

Read the config as blocks. A well-formed proxy location closes every brace it opens:

server {
    listen 443 ssl;
    server_name app.example.com;

    location /api/ {
        proxy_pass http://backend;
        proxy_set_header Host $host;
    }          # <-- this closing brace is the one commonly forgotten

    location / {
        root /var/www/app;
    }
}              # <-- and the server block's own closing brace

If a brace legitimately belongs in a value, quote the whole value so NGINX doesn’t treat it as a block:

log_format json '{ "ip":"$remote_addr", "uri":"$request_uri" }';

Re-validate after each change:

nginx -t && nginx -s reload

Example Root Cause Analysis

A reload started failing with unexpected end of file, expecting "}" in /etc/nginx/nginx.conf:96 — the very last line of the main file. Nothing on line 96 was wrong; it was the closing brace of the http {} block. The brace-count loop immediately flagged the real offender: /etc/nginx/conf.d/api.conf had open=7 close=6.

An engineer had added a new location /internal/ { ... } block but, while copy-pasting, dropped its closing }. Because conf.d/*.conf is included inside http {}, NGINX kept parsing past the intended end of that location, consumed the rest of the file and the include boundary, and only noticed something was wrong when it hit the final brace of nginx.conf. Adding the missing } to api.conf fixed it. Running nginx -T afterward confirmed the block nesting was correct in the assembled config.

Prevention Best Practices

  • When the error points at the last line of a file, don’t stare at that line — run a brace-count across every config and included snippet to find the real imbalance.
  • Use nginx -T to view the fully assembled config; it makes cross-file nesting problems obvious.
  • Edit with an editor that matches and highlights braces, and fold blocks so an unclosed one is visually obvious.
  • Add and close a block in the same edit — write location /x/ { } first, then fill it in, so the closing brace is never forgotten.
  • Quote any value that legitimately contains { or } (JSON log formats, some headers) so NGINX doesn’t parse it as a block.
  • Keep conf.d/sites-enabled snippets small and self-contained so a brace error is localized to one reviewable file.

Quick Command Reference

# Find the file with unbalanced braces
for f in /etc/nginx/nginx.conf /etc/nginx/conf.d/*.conf; do
  o=$(grep -o '{' "$f" | wc -l); c=$(grep -o '}' "$f" | wc -l)
  [ "$o" != "$c" ] && echo "$f open=$o close=$c"; done

# Validate and see the assembled config
nginx -t
nginx -T | less

# Reload after fixing
nginx -t && nginx -s reload

Conclusion

unexpected end of file, expecting "}" means a block was opened and never closed, and NGINX ran off the end of the input still waiting for the brace. The reported line is where parsing stopped, not where the bug is — so count braces across nginx.conf and every included file, use nginx -T to inspect nesting, and quote any braces that live inside string values. Balance the pair, re-run nginx -t, and the reload will succeed.

Free download · 368-page PDF

Fixed it? Get 500 NGINX & DevOps AI prompts — free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.

Did this fix your issue?

Free download · 368-page PDF

Get 500 Battle-Tested DevOps AI Prompts — Free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.