{"record":{"id":"86096ce71b01e23b","repo":"666ghj/MiroFish","slug":"github-api-returned-an-invalid-stargazers-count","errorCode":null,"errorMessage":"GitHub API returned an invalid stargazers_count","messagePattern":"GitHub API returned an invalid stargazers_count","errorType":"exception","errorClass":"FetchError","httpStatus":null,"severity":"error","filePath":"scripts/fetch_star_count.py","lineNumber":122,"sourceCode":"                raise _status_error(status)\n            payload = _read_response(response)\n    except FetchError:\n        raise\n    except (TimeoutError, OSError):\n        raise FetchError(\"GitHub API response could not be read\") from None\n    except Exception:\n        raise FetchError(\"GitHub API response could not be processed\") from None\n\n    try:\n        document = json.loads(payload)\n    except (UnicodeDecodeError, json.JSONDecodeError, ValueError):\n        raise FetchError(\"GitHub API returned malformed JSON\") from None\n    if not isinstance(document, dict):\n        raise FetchError(\"GitHub API response had an unexpected shape\")\n\n    count = document.get(\"stargazers_count\")\n    if type(count) is not int or count < 0:\n        raise FetchError(\"GitHub API returned an invalid stargazers_count\")\n    return count\n\n\ndef main(argv: list[str] | None = None) -> int:\n    arguments = sys.argv[1:] if argv is None else argv\n    if arguments:\n        print(\"error: this command accepts no arguments\", file=sys.stderr)\n        return 2\n\n    try:\n        count = fetch_star_count(os.environ.get(\"GITHUB_TOKEN\", \"\"))\n    except FetchError as exc:\n        print(f\"error: {exc}\", file=sys.stderr)\n        return 1\n    except Exception:\n        print(\"error: unexpected internal failure\", file=sys.stderr)\n        return 1\n","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/666ghj/MiroFish/blob/b5b53acc57189a4a42e44a23e149dc655c98fe82/scripts/fetch_star_count.py#L104-L140","documentation":"Final contract check on the payload: document['stargazers_count'] must be an int (strictly — type(count) is not int rejects bool, float, and numeric strings) and >= 0. The strictness is deliberate: JSON true is an int subclass in Python, and float counts would indicate a tampered or non-GitHub response.","triggerScenarios":"A JSON proxy serializing counts as strings ('12345') or floats; a mock payload omitting stargazers_count (None) or using stargazersCount (camelCase, wrong field name); a boolean sneaking in via a lossy JSON re-encoder.","commonSituations":"Test fixtures with the wrong key or type; third-party GitHub-compatible APIs (Enterprise Server mirrors, api caches) that serialize differently; response-shape drift after a GitHub API version change (X-GitHub-Api-Version header pinned to API_VERSION).","solutions":["Check the exact field: curl the API and verify the key is stargazers_count (snake_case) in the returned object.","If integrating a non-GitHub-compatible endpoint, map its field and coerce types before calling, or adapt the script; do not loosen the strict int check for real GitHub responses.","Fix test doubles to return {'stargazers_count': 42} with a true JSON number."],"exampleFix":"# before (test fixture)\nbody = json.dumps({\"stargazersCount\": 42.0})  # wrong key, float\n\n# after\nbody = json.dumps({\"stargazers_count\": 42})","handlingStrategy":"validation","validationCode":"import json, urllib.request\n\n# pre-validate against a fetched document before relying on the strict parser\nwith urllib.request.urlopen(\"https://api.github.com/repos/666ghj/MiroFish\") as r:\n    doc = json.load(r)\nvalue = doc.get(\"stargazers_count\")\nassert type(value) is int and value >= 0, f\"unexpected count field: {value!r}\"","typeGuard":"def is_valid_star_count(value: object) -> bool:\n    \"\"\"Strict int (bool rejected), non-negative.\"\"\"\n    return type(value) is int and value >= 0","tryCatchPattern":"try:\n    count = fetch_star_count(token)\nexcept FetchError as exc:\n    if exc.args[0] == \"GitHub API returned an invalid stargazers_count\":\n        raise SystemExit(\n            \"field missing/wrong type; real GitHub always returns int \"\n            \"stargazers_count — inspect the raw payload\"\n        )\n    raise","preventionTips":["Use type(x) is int (not isinstance) when bool exclusion matters.","Snapshot a real API response into tests so field-name drift (stargazersCount vs stargazers_count) fails fast.","When proxying GitHub responses through your own service, re-serialize numbers as JSON numbers, never strings."],"tags":["json","type-check","api-contract","fetch-star-count"],"backgroundTag":null,"analyzedSha":"b5b53acc57189a4a42e44a23e149dc655c98fe82","analyzedAt":"2026-08-14T22:29:33.146Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}