air-verse/air · error
proxy inject: failed to init gzip reader
Error message
proxy inject: failed to init gzip reader: %w
What it means
When proxying, injectLiveReload detects a gzip Content-Encoding header and wraps resp.Body in gzip.NewReader to read the decompressed HTML before injecting the reload script. If the gzip stream is corrupt or empty, this error is returned.
Solutions
- Fix the upstream app so it only sets Content-Encoding: gzip when it actually compresses the body
- Disable compression in the upstream app/middleware so air receives plain responses
- Check the wrapped %w error: gzip.ErrHeader / unexpected EOF indicate corrupt or truncated streams
- Bypass other compression layers (CDN/ingress) between air's proxy and the app
Example fix
// before (upstream app)
w.Header().Set("Content-Encoding", "gzip")
w.Write([]byte(html)) // not actually gzipped
// after
w.Write([]byte(html)) // let the framework compress or drop the header Defensive patterns
Strategy: try-catch
Validate before calling
// verify upstream doesn't lie about gzip
resp, _ := http.Get("http://localhost:" + appPort + "/")
if resp.Header.Get("Content-Encoding") == "gzip" {
zr, err := gzip.NewReader(resp.Body)
if err != nil {
log.Printf("upstream sends invalid gzip: %v", err)
}
_ = zr
} Try / catch
if err := startProxy(); err != nil && strings.Contains(err.Error(), "failed to init gzip reader") {
// disable compression upstream, then retry
} Prevention
- Only set Content-Encoding: gzip when actually compressing
- Prefer framework-managed compression (middleware) over manual headers
- Test the app directly (curl --compressed) before proxying through air
- Keep dev-mode compression off for simpler proxying
When it happens
Trigger: The upstream app responds with Content-Encoding: gzip but the body is not valid gzip data — e.g. the app sets the header manually but sends uncompressed bytes, or the stream is truncated.
Common situations: Backend frameworks double-encoding or lying about the encoding header; middleware setting Content-Encoding: gzip without actually compressing; proxying non-Golang servers with broken compression middleware.
Related errors
- proxy handler: bad form
- proxy handler: unable to create request
- proxy inject: failed to read body from http response
AI-assisted analysis of air-verse/air@71ea1dee05 (2026-08-31).
Data as JSON: /api/errors/34f9230641cabcc2.
Report an issue: GitHub.
Appendix: source
Thrown at runner/proxy.go:125
}
func (p *Proxy) Reload() {
p.stream.Reload()
}
func (p *Proxy) BuildFailed(msg BuildFailedMsg) {
p.stream.BuildFailed(msg)
}
func (p *Proxy) injectLiveReload(resp *http.Response) (string, bool, error) {
var reader io.Reader = resp.Body
decoded := false
switch detectContentEncoding(resp.Header) {
case encodingGzip:
gzipReader, err := gzip.NewReader(resp.Body)
if err != nil {
return "", false, fmt.Errorf("proxy inject: failed to init gzip reader: %w", err)
}
defer gzipReader.Close()
reader = gzipReader
decoded = true
case encodingBrotli:
reader = brotli.NewReader(resp.Body)
decoded = true
}
buf := new(bytes.Buffer)
if _, err := buf.ReadFrom(reader); err != nil {
return "", decoded, fmt.Errorf("proxy inject: failed to read body from http response: %w", err)
}
page := buf.String()
// the script will be injected before the end of the body tag. In case the tag is missing, the injection will be skipped with no error.
body := strings.LastIndex(page, "</body>")
if body == -1 {View on GitHub (pinned to 71ea1dee05)