Repository navigation
fix: raise SnowflakeForbiddenError for HTTP 403 - #22
Conversation
- A 403 means Snowflake accepted the JWT and refused the request, which callers want to tell apart from a malformed request without parsing status_code. It now raises SnowflakeForbiddenError instead of the generic SnowflakeRequestError. - SnowflakeForbiddenError subclasses SnowflakeRequestError, so every existing except SnowflakeRequestError still catches a 403 (non-breaking). - It carries status_code, code, sql_state and statement_handle like the generic branch, and is exported from the package root. - Sync and async regression tests cover the mapping; troubleshooting and authentication docs gain a 403 section.
- troubleshooting: the default RetryPolicy does not retry a 403; a custom policy listing it surfaces SnowflakeRetryError with a plain SnowflakeRequestError cause. - testing.md: show register_error(status=403) raising SnowflakeForbiddenError. - transport module docstring reflowed to the line length.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: ⚪ Minimal · up to
|
Summary
A 403 means Snowflake accepted the JWT and refused the request (for example, the SQL API is
not enabled for the account). Callers can now tell that apart from a
malformed request without parsing
status_code: HTTP 403 raisesSnowflakeForbiddenError.SnowflakeForbiddenErrorsubclassesSnowflakeRequestErrorand carries the samestatus_code,code,sql_stateandstatement_handle; exported from the package root_interpret, so sync and async clients get it, on submit,status polls, partition fetches and cancel alike
retry_statuses, so it fails fast. A customRetryPolicythatlists 403 still surfaces
SnowflakeRetryErrorwith a plainSnowflakeRequestErrorcause,the same as every other retried status
docs/troubleshooting.md(causes, and that an object-privilegefailure is a 422, not a 403), a pointer in
docs/authentication.md, and aregister_error(status=403)example indocs/testing.md. The causes follow theSQL API reference
response-code table, which names "API not enabled"; the network-policy case is worded
conditionally on the message naming an IP
Docs: updated
Backwards compatibility
Non-breaking. Every
except SnowflakeRequestErrorandisinstancecheck still matches a403. Only code testing
type(exc) is SnowflakeRequestErrorsees a difference.Review
its own delta by both: clean, 1 low test ask applied (385117c).
tests/test_transport.pynothing to apply.
tests/test_regression.py:127:route.call_count == 1does not discriminateretry behaviour; the
pytest.raisestype does (mention)tests/test_transport.py:169: the untyped exhausted-retry cause is now a testedcontract, so mapping
_retry_errorby status later changes this test and the doc linetogether (mention)
snowflake_sql_api/transport.py:307: no test exercisesAsyncTransportretry orexhaustion; predates this change (mention)
docs/testing.md:78: no test drivesregister_error(status=403); the regressiontests guard the mapping it passes through (mention)
API reference
Changes
Test plan
test_regression_403_raises_forbidden_errorand its async twin; both fail with the 403branch removed
test_custom_policy_retrying_403_chains_plain_request_error; fails when_retry_errormaps 403 to the forbidden type
coverage run -m pytest: 194 passed, 5 skipped, 94% coveragepre-commit run --all-filescleanSummary by CodeRabbit
SnowflakeForbiddenErrorfor HTTP 403 responses, available through the package’s public interface. Existing request-error handlers also catch it.