AsyncOpenSearch 403s where sync works: async rewrites HEAD to GET
Shows how to fix asyncOpenSearch 403s where sync works: async rewrites HEAD to GET. Use it when you hit this exact problem. Skip it when your error message or symptom looks different.
TL;DR
Resolution: upgrade opensearch-py past 2.4.x to a release containing #794. Client bug, confirmed and fixed.
Steps
- Client bug, confirmed and fixed. The async connection classes (AsyncHttpConnection and AIOHttpConnection) rewrite every HEAD request as GET, a leftover workaround for an old aiohttp connection-reuse bug that was fixed upstream years ago (aiohttp#5012). Under SigV4 IAM auth with a tight policy, that silent HEAD-to-GET conversion turns into a 403, which is why sync works and async does not. The reporter verified the mechanism, and the fix shipped in opensearch-py PR #794, which stops the conversion. Resolution: upgrade opensearch-py past 2.4.x to a release containing #794. Until then, avoid bare ping() under locked-down IAM policies and call an index-scoped endpoint instead.
Expected: The reporter verified the mechanism, and the fix shipped in opensearch-py PR #794, which stops the conversion.
When to use
You are seeing this: Issue opensearch-project/opensearch-py#698 (closed, 10 comments): AsyncOpenSearch with AWSV4SignerAsyncAuth fails with 403 on ping() while the exact same sync code returns 200. Use this skill when you run into "AsyncOpenSearch 403s where sync works: async rewrites HEAD to GET".
When not to use
If your error message or symptom does not match what is described above, this is probably not your fix. Search for your exact error text instead of forcing this one to fit.
Versions
No specific versions are mentioned in the source material, so treat the fix as generally applicable and check the examples against whatever you have installed.
Why this happens
The original report does not dig into a root cause. It documents the symptom and the fix that resolved it.
Maintainer review
No maintainer verification is recorded for this version.
This records the version a maintainer checked. It does not assert that the version is the latest upstream release.