DEV Community

engnzdl
engnzdl

Posted on

Two real bugs in aiograpi: a race condition and a dropped auth token

aiograpi is the async Instagram private-API library (475★ on GitHub). A version bump of our vendored copy surfaced two real bugs. Both are fixed, tested, and PR'd upstream.

1. photo_upload extracts media from the wrong response

photo_upload retries photo_configure up to 10 times, then pulls the uploaded media out of self.last_json:

if await self.photo_configure(...):
    media = await self._extract_configured_media_or_recent(
        self.last_json,   # shared mutable state
        ...
    )
Enter fullscreen mode Exit fullscreen mode

self.last_json is the client's shared "last response" field. In a single-upload flow it happens to equal the configure response. Run two uploads concurrently and another coroutine's response can land in self.last_json between the configure call and the read — you extract media from the wrong request, or fail outright.

photo_configure already returns the configured dict. The retry loop was discarding it:

if configure_result := await self.photo_configure(...):
    media = await self._extract_configured_media_or_recent(
        configure_result,
        ...
    )
Enter fullscreen mode Exit fullscreen mode

Race gone.

2. Instagram's token rotation gets silently dropped

Instagram rotates the bearer token mid-session and returns it in the ig-set-authorization response header. aiograpi parsed that header in exactly one place — the login flow. A rotation returned on any other private request was dropped, so authorization_data went stale and every later request rebuilt a stale Authorization header.

The fix moves the parse into the shared private-request handler, so any response carrying the header updates the client:

authorization = response.headers.get("ig-set-authorization")
if authorization:
    self.authorization_data = self.parse_authorization(authorization)
Enter fullscreen mode Exit fullscreen mode

Shipped with tests

Each fix has a regression test (mocked transport / mocked configure) and passes the project's ruff + pytest gates.

Top comments (0)