hashicorp/terraform · error

response has invalid Content-Type

Error message

response has invalid Content-Type: %s

What it means

For a 200 response, the client parses the `Content-Type` header with `mime.ParseMediaType`. If the header value is malformed (e.g. unparseable parameters, stray characters), the parse error is surfaced. This is distinct from a wrong-but-well-formed media type.

Solutions

  1. Capture the raw `Content-Type` header with `curl -i` and inspect it.
  2. Fix the mirror server / reverse proxy to emit a clean `Content-Type: application/json`.
  3. Remove any middleware that rewrites headers incorrectly.

Example fix

// before
Content-Type: application/json; charset=
// after
Content-Type: application/json
Defensive patterns

Strategy: validation

Validate before calling

// Validate Content-Type well-formedness before sending the response
ct := resp.Header.Get("Content-Type")
if _, _, err := mime.ParseMediaType(ct); err != nil {
    return fmt.Errorf("mirror sent malformed Content-Type %q: %w", ct, err)
}

Type guard

// isValidContentType narrows to parseable header values
func isValidContentType(ct string) bool {
    _, _, err := mime.ParseMediaType(ct)
    return err == nil
}

Prevention

When it happens

Trigger: `mime.ParseMediaType(ct)` returns an error for the response's `Content-Type` header; error at http_mirror_source.go:377.

Common situations: Mirror/proxy sends a malformed `Content-Type` (missing closing quote, illegal chars); custom header injection by an intermediary; rare misconfigured CDN.

Related errors


AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11). Data as JSON: /api/errors/fe755b697b100e15. Report an issue: GitHub.

Appendix: source

Thrown at internal/getproviders/http_mirror_source.go:377

	defer func() {
		// If we're not returning the body then we'll close it
		// before we return.
		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

View on GitHub (pinned to d32a084675)