{"record":{"id":"940785bfc41cc840","repo":"github/copilot-sdk","slug":"failed-to-parse-package-json-w","errorCode":null,"errorMessage":"failed to parse package.json: %w","messagePattern":"failed to parse package\\.json: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/cmd/bundler/main.go","lineNumber":338,"sourceCode":"\turl := fmt.Sprintf(packageJSONURLFmt, gitRef)\n\tfmt.Printf(\"Fetching %s...\\n\", url)\n\n\tresp, err := http.Get(url)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to fetch: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn \"\", fmt.Errorf(\"failed to fetch package.json: %s\", resp.Status)\n\t}\n\n\tvar packageJSON struct {\n\t\tCopilotCLIVersion string `json:\"copilotCliVersion\"`\n\t}\n\n\tif err := json.NewDecoder(resp.Body).Decode(&packageJSON); err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to parse package.json: %w\", err)\n\t}\n\n\tif packageJSON.CopilotCLIVersion == \"\" {\n\t\treturn fetchLegacyCLIVersionFromRepo(gitRef)\n\t}\n\n\treturn packageJSON.CopilotCLIVersion, nil\n}\n\nfunc fetchLegacyCLIVersionFromRepo(gitRef string) (string, error) {\n\turl := fmt.Sprintf(packageLockURLFmt, gitRef)\n\tfmt.Printf(\"Falling back to %s...\\n\", url)\n\n\tresp, err := http.Get(url)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to fetch legacy package-lock.json: %w\", err)\n\t}\n\tdefer resp.Body.Close()","sourceCodeStart":320,"sourceCodeEnd":356,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/go/cmd/bundler/main.go#L320-L356","documentation":"After a successful 200 fetch, the body is JSON-decoded into a struct expecting a `copilotCliVersion` field. Malformed JSON is wrapped as 'failed to parse package.json'. This means the fetched file exists but its contents are not valid JSON in the expected shape.","triggerScenarios":"The URL returns HTML (e.g. a 200 error page or rate-limit interstitial), a truncated body, or the package.json at that ref has invalid/differently-encoded JSON.","commonSituations":"Proxy or captive portal returning an HTML 200 page; an SDK ref where package.json was corrupted or moved; extremely rare — transient network truncation mid-body.","solutions":["curl the printed URL and inspect what was actually returned (often HTML instead of JSON)","Fix proxy/captive-portal issues so the raw JSON file is served","Retry if the body was truncated by a transient network error","Pin a released SDK version whose package.json is valid"],"exampleFix":"// before: failed to parse package.json: invalid character '<' looking for beginning of value\n// after: bypass proxy / retry so raw package.json is fetched and parses cleanly","handlingStrategy":"validation","validationCode":"body, _ := io.ReadAll(resp.Body)\nif !bytes.HasPrefix(bytes.TrimSpace(body), []byte(\"{\")) {\n    return fmt.Errorf(\"expected JSON, got: %.80s\", body)\n}\nvar pkg struct{ CopilotCLIVersion string `json:\"copilotCliVersion\"` }\nif err := json.Unmarshal(body, &pkg); err != nil {\n    return fmt.Errorf(\"bad package.json: %v\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := json.NewDecoder(resp.Body).Decode(&pkg); err != nil {\n    var jsonErr *json.SyntaxError\n    if errors.As(err, &jsonErr) {\n        // log offset jsonErr.Offset, capture body for diagnostics, retry or fail loudly\n    }\n}","preventionTips":["Verify fetched bodies start with '{' before decoding (catches HTML 200 pages)","Capture and log the response body on decode failure","Retry transient truncations with backoff"],"tags":["json","http","parsing","github"],"backgroundTag":"json-parse-error","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}