{"record":{"id":"e01fac95a6683fc1","repo":"github/github-mcp-server","slug":"decoding-installation-token-response-w","errorCode":null,"errorMessage":"decoding installation token response: %w","messagePattern":"decoding installation token response: %w","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/githubapp/githubapp.go","lineNumber":166,"sourceCode":"\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"requesting installation token: %w\", err)\n\t}\n\tdefer func() { _ = resp.Body.Close() }()\n\n\tif resp.StatusCode != http.StatusCreated {\n\t\tsnippet, readErr := io.ReadAll(io.LimitReader(resp.Body, 512))\n\t\tif readErr != nil {\n\t\t\treturn nil, fmt.Errorf(\"installation token request failed: %s (reading response: %w)\", resp.Status, readErr)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"installation token request failed: %s: %s\", resp.Status, strings.TrimSpace(string(snippet)))\n\t}\n\n\tvar body struct {\n\t\tToken     string    `json:\"token\"`\n\t\tExpiresAt time.Time `json:\"expires_at\"`\n\t}\n\tif err := json.NewDecoder(resp.Body).Decode(&body); err != nil {\n\t\treturn nil, fmt.Errorf(\"decoding installation token response: %w\", err)\n\t}\n\tif body.Token == \"\" {\n\t\treturn nil, errors.New(\"installation token response did not contain a token\")\n\t}\n\tif body.ExpiresAt.IsZero() {\n\t\treturn nil, errors.New(\"installation token response did not contain an expiry\")\n\t}\n\treturn &oauth2.Token{\n\t\tAccessToken: body.Token,\n\t\tTokenType:   \"token\",\n\t\tExpiry:      body.ExpiresAt.Add(-refreshBuffer),\n\t}, nil\n}\n\n// Provider caches and refreshes GitHub App installation access tokens.\ntype Provider struct {\n\tsource oauth2.TokenSource\n\tlogger *slog.Logger","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/github/github-mcp-server/blob/0ea1f775a7c73eff1bd2e25904d01136756bbfe2/internal/githubapp/githubapp.go#L148-L184","documentation":"The endpoint returned 201 Created but the JSON decoder could not parse the body: the response is not valid JSON matching {token, expires_at}. Since genuine GitHub responses are well-formed JSON, this points at an intercepting proxy returning HTML, a GHES misconfiguration, or a body truncated mid-transfer. The %w wrap exposes the encoding/json error (e.g. 'invalid character < looking for beginning of value').","triggerScenarios":"A captive portal / corporate MITM proxy answers 201 with an HTML page; a GHES appliance returns a non-JSON success payload for the api/v3 path; a body larger than the connection's content-length that got cut, causing 'unexpected EOF' in json.NewDecoder(...).Decode at internal/githubapp/githubapp.go:165.","commonSituations":"Guest/hotel Wi-Fi captive portal intercepting HTTPS via an installed trust root; an internal API gateway fronting GHES that rewrites responses; flaky links truncating bodies; HTTP/2 downgrade middleboxes corrupting framing.","solutions":["Read the wrapped json error: 'invalid character <' means HTML (proxy/captive portal) — inspect what actually answers with curl -k -v","Set NO_PROXY for the API host or fix HTTPS_PROXY so the GitHub endpoint is not MITM'd","For GHES, confirm BaseRESTURL is exactly https://HOST/api/v3/ and the appliance version is current","Retry on 'unexpected EOF' — truncation is often transient"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if strings.Contains(err.Error(), \"invalid character\") {\n    // HTML body: a proxy/captive portal answered — inspect with curl, fix proxy config\n}","preventionTips":["Add api.github.com / the GHES host to NO_PROXY when an HTTPS MITM proxy is present","Pin BaseRESTURL to the documented GHES path https://HOST/api/v3/ and keep GHES updated"],"tags":["proxy","json","network","github-enterprise","http"],"backgroundTag":null,"analyzedSha":"0ea1f775a7c73eff1bd2e25904d01136756bbfe2","analyzedAt":"2026-08-15T18:10:19.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}