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 media type, get() requires it to be exactly application/json. Any other media type (text/html, application/octet-stream, etc.) on a 200 response yields this error. Typically means an error/landing page was served with status 200 instead of the JSON index.
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 c9def3e214)
Solutions
- Configure the mirror server to serve .json files as application/json.
- Point the base URL at the exact directory containing index.json and the version files.
- Remove catch-all routes that return HTML with 200 for missing paths.
Example fix
# before: nginx default type for unknown ext
http {
default_type application/octet-stream;
}
# after
http {
types {
application/json json;
}
default_type application/octet-stream;
} Defensive patterns
Strategy: try-catch
Validate before calling
// Preflight: require a JSON media type from the mirror.
mt, _, _ := mime.ParseMediaType(resp.Header.Get("Content-Type"))
if mt != "application/json" {
return fmt.Errorf("expected application/json, got %q", mt)
} Try / catch
if err != nil && strings.Contains(err.Error(), "must be application/json") {
// mirror served a non-JSON 200; report, do not retry
} Prevention
- Map the .json extension to application/json on the mirror web server.
- Disable catch-all routes that return HTML with 200.
- Point the base URL at the directory holding index.json.
When it happens
Trigger: Mirror or an intermediary returns 200 with a non-JSON body: a generic HTML page, a directory listing, or a binary. Common when a static file server doesn't set .json Content-Type or a proxy serves a fallback page.
Common situations: Mirror directory served by a web server without the .json MIME mapping; catch-all route returning an HTML SPA page with 200; wrong base URL path landing on a listing page.
Related errors
- response has invalid Content-Type: %s
- too many redirects
- server returned unsuccessful status %d
- invalid response content from mirror server: %s
- provider mirror does not have archive index for previously-r
AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07).
Data as JSON: /api/errors/3090137606c60b2f.
Report an issue: GitHub.