Skip to content

fix: REST fallback must not re-create the BigQuery Storage client - #19

Merged
Burdantes merged 2 commits into
mainfrom
fix/read-df-fallback-recreates-storage-client
Aug 9, 2026
Merged

Burdantes merged 2 commits into
mainfrom
fix/read-df-fallback-recreates-storage-client

Conversation

@Burdantes

Copy link
Copy Markdown
Collaborator

Follow-up to #18, which exposed a latent bug in the tomography download fallback.

The bug

_read_df (correlation_tomography.py) catches a Storage Read API failure and retries:

except Exception as exc:
    logger.warning("  Storage Read API unavailable (%s); using REST download", exc)
    return query_job.to_dataframe()          # <-- create_bqstorage_client defaults to True

to_dataframe() defaults to create_bqstorage_client=True, so whenever google-cloud-bigquery-storage is importable the fallback builds its own Storage client — re-attempting the very thing it is falling back from, and re-raising the identical error.

Latent while the package was absent (the import failed first, so the retry had nothing to auto-create). #18 installed the package and every Phase D died with 403 ... 'bigquery.readsessions.create', logged immediately after "using REST download".

Verified against the live identity

call result
to_dataframe() FAILPermissionDenied: 403 ... readsessions.create
to_dataframe(create_bqstorage_client=False) OK

This is also an IAM gap

The pipeline's ADC identity is loqman@measurementlab.net, which lacks roles/bigquery.readSessionUser on mlab-collaboration. Until that is granted the Arrow path is unavailable and this degrades to REST — which works, but is slower and much heavier: a 13.7M-row download OOM-killed the worker at 22.1 GB inside a 28 GB cgroup, failing the 2025-08 backfill chunk. Granting the role would both fix that OOM and cut ~20 min off every nightly Phase D.

Testing

4 new tests in test_read_df_fallback.py, including a regression test that fails against the old code (the fallback's kwargs were empty). Full suite 59 passed, 2 skipped on 3.14; ruff check and format clean.

🤖 Generated with Claude Code

Burdantes and others added 2 commits August 8, 2026 18:07
_read_df catches a Storage Read API failure and retries with a bare
query_job.to_dataframe(). That argument defaults to create_bqstorage_client=True,
so whenever google-cloud-bigquery-storage is importable the fallback silently
builds its own Storage client — re-attempting the exact thing it is falling back
from and re-raising the identical error.

This was latent while the package was absent: the import failed first, so the
retry had nothing to auto-create and REST genuinely worked. Installing the
package in #18 exposed it, and every Phase D died with

  403 ... does not have 'bigquery.readsessions.create' permission

logged immediately after "using REST download". Verified against the live
identity: to_dataframe() fails, to_dataframe(create_bqstorage_client=False)
succeeds.

Note this is a per-identity IAM question as well as a packaging one. The
pipeline's ADC identity is loqman@measurementlab.net, which lacks
roles/bigquery.readSessionUser on mlab-collaboration. Until that is granted the
Arrow path is unavailable and this degrades to REST — which works, but is slower
and much heavier: a 13.7M-row download OOM-killed the worker at 22.1 GB inside a
28 GB cgroup and failed the 2025-08 backfill chunk.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The first version sequenced job.to_dataframe side effects assuming
BigQueryReadClient() would construct successfully. That holds on a machine with
application-default credentials but not in CI, where construction raises first
and the Arrow call never happens — so the side_effect list lined up differently
and three tests failed. They passed locally for the wrong reason.

Drive both branches explicitly with a fake google.cloud.bigquery_storage module
whose client constructor can be made to raise, covering the two real-world
cases (missing ADC, and the 403 when the identity lacks
bigquery.readsessions.create). Verified passing both with ambient ADC and with
credentials stripped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Burdantes
Burdantes merged commit 0d8e90d into main Aug 9, 2026
4 checks passed
@Burdantes
Burdantes deleted the fix/read-df-fallback-recreates-storage-client branch August 9, 2026 00:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant