hashicorp/terraform · error
response has invalid Content-Type: must be application/json
Error message
response has invalid Content-Type: must be application/json
What it means
After successfully parsing the `Content-Type`, the client asserts the parsed media type is exactly `application/json`. Any other media type (e.g. `text/html`, `application/octet-stream`) on a 200 response triggers this error.
Solutions
- Configure the mirror to send `Content-Type: application/json` for index responses.
- Check for default-catch-all pages served by the mirror host.
- `curl -i` the URL and confirm the header.
Example fix
// before
Content-Type: text/html
...<html>...
// after
Content-Type: application/json
{"versions":{...}} Defensive patterns
Strategy: validation
Validate before calling
// Verify the served media type
mt, _, _ := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if mt != "application/json" {
return fmt.Errorf("mirror content type %q is not application/json", mt)
} Type guard
// isJSONMediaType narrows to application/json responses
func isJSONMediaType(ct string) bool {
mt, _, err := mime.ParseMediaType(ct)
return err == nil && mt == "application/json"
} Prevention
- Always set `Content-Type: application/json` on the mirror.
- Don't serve HTML error pages with status 200.
- Test with `curl -i`.
- Default server fallbacks should return non-200, not 200+HTML.
When it happens
Trigger: `mime.ParseMediaType` succeeds but `mt != "application/json"`; error at http_mirror_source.go:380.
Common situations: Mirror serves an HTML page with status 200; mirror serves JSON as `text/plain`; CDN/default fallback returns a generic page; misconfigured reverse proxy default type.
Related errors
- response has invalid Content-Type
- failed to determine request credentials
- invalid credentials for
- invalid provider mirror base URL
- invalid response content from mirror server
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/3090137606c60b2f.
Report an issue: GitHub.
Appendix: source
Thrown at internal/getproviders/http_mirror_source.go:380
if body == nil {
resp.Body.Close()
}
}()
// After this point, our final URL return value should always be the
// one from resp.Request, because that takes into account any redirects
// we followed along the way.
finalURL = resp.Request.URL
if resp.StatusCode == http.StatusOK {
// If and only if we get an OK response, we'll check that the response
// type is JSON and return the body reader.
ct := resp.Header.Get("Content-Type")
mt, params, err := mime.ParseMediaType(ct)
if err != nil {
return 0, nil, finalURL, fmt.Errorf("response has invalid Content-Type: %s", err)
}
if mt != "application/json" {
return 0, nil, finalURL, fmt.Errorf("response has invalid Content-Type: must be application/json")
}
for name := range params {
// The application/json content-type has no defined parameters,
// but some servers are configured to include a redundant "charset"
// parameter anyway, presumably out of a sense of completeness.
// We'll ignore them but warn that we're ignoring them in case the
// subsequent parsing fails due to the server trying to use an
// unsupported character encoding. (RFC 7159 defines its own
// JSON-specific character encoding rules.)
log.Printf("[WARN] Network mirror returned %q as part of its JSON content type, which is not defined. Ignoring.", name)
}
body = resp.Body
}
return resp.StatusCode, body, finalURL, nil
}
func (s *HTTPMirrorSource) errQueryFailed(provider addrs.Provider, err error) error {View on GitHub (pinned to d32a084675)