github/copilot-sdk · error
failed to parse package.json
Error message
failed to parse package.json: %w
What it means
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.
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
Example fix
// before: failed to parse package.json: invalid character '<' looking for beginning of value // after: bypass proxy / retry so raw package.json is fetched and parses cleanly
Defensive patterns
Strategy: validation
Validate before calling
body, _ := io.ReadAll(resp.Body)
if !bytes.HasPrefix(bytes.TrimSpace(body), []byte("{")) {
return fmt.Errorf("expected JSON, got: %.80s", body)
}
var pkg struct{ CopilotCLIVersion string `json:"copilotCliVersion"` }
if err := json.Unmarshal(body, &pkg); err != nil {
return fmt.Errorf("bad package.json: %v", err)
} Try / catch
if err := json.NewDecoder(resp.Body).Decode(&pkg); err != nil {
var jsonErr *json.SyntaxError
if errors.As(err, &jsonErr) {
// log offset jsonErr.Offset, capture body for diagnostics, retry or fail loudly
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- failed to parse legacy package-lock.json
- Unexpected trailing content at position
- Unescaped control character at position <pos-1>
- Unterminated string escape at position
- Invalid escape sequence \
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/940785bfc41cc840.
Report an issue: GitHub.
Appendix: source
Thrown at go/cmd/bundler/main.go:338
url := fmt.Sprintf(packageJSONURLFmt, gitRef)
fmt.Printf("Fetching %s...\n", url)
resp, err := http.Get(url)
if err != nil {
return "", fmt.Errorf("failed to fetch: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("failed to fetch package.json: %s", resp.Status)
}
var packageJSON struct {
CopilotCLIVersion string `json:"copilotCliVersion"`
}
if err := json.NewDecoder(resp.Body).Decode(&packageJSON); err != nil {
return "", fmt.Errorf("failed to parse package.json: %w", err)
}
if packageJSON.CopilotCLIVersion == "" {
return fetchLegacyCLIVersionFromRepo(gitRef)
}
return packageJSON.CopilotCLIVersion, nil
}
func fetchLegacyCLIVersionFromRepo(gitRef string) (string, error) {
url := fmt.Sprintf(packageLockURLFmt, gitRef)
fmt.Printf("Falling back to %s...\n", url)
resp, err := http.Get(url)
if err != nil {
return "", fmt.Errorf("failed to fetch legacy package-lock.json: %w", err)
}
defer resp.Body.Close()View on GitHub (pinned to cd8cf15dc3)