Retrying a multipart request raises "Cannot write to closed encoder"
Les mainteneurs répondent en général sous 1 jour
Évaluation
- Difficulté
- 3/5
- Temps estimé
- 1-2 jours
- Accessibilité débutants
- 56/100
Piste de recherche
Start with lib/auth0/internal/multipart/multipart_form_data.rb and lib/auth0/internal/multipart/multipart_encoder.rb, then trace the retry loop in lib/auth0/internal/http/raw_client.rb and header construction in Multipart::Request#encode_headers. Reproduce with the provided WebMock example and verify retries resend the multipart body with a consistent boundary; after retries are exhausted, the client should raise Auth0::Errors::ClientError for a 429.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Description
Checklist
- I have looked into the Readme and Examples, and have not found a suitable solution or answer.
- I have looked into the API documentation and have not found a suitable solution or answer.
- I have searched the issues and have not found a suitable solution or answer.
- I have searched the Auth0 Community forums and have not found a suitable solution or answer.
- I agree to the terms within the Auth0 Code of Conduct.
Description
When a multipart request gets a retryable status (429 or 5xx), Internal::Http::RawClient#send retries it and calls request.encode_body again. Internal::Multipart::FormData keeps a single Encoder, which is closed after the first encode, so the second call raises RuntimeError: Cannot write to closed encoder from Encoder#write_part. The retry is never sent.
This affects jobs.users_imports.create, the multipart endpoint we use. Any 429 or 5xx on a users import comes back as a RuntimeError, so callers that rescue Auth0::Errors::ResponseError don't see it.
Expected: the retry sends the same multipart body again, and once retries run out the client raises the API error (Auth0::Errors::ClientError for a 429), as it does for JSON requests.
Reproduction
Reproducible every time with the default management_max_retries:
require "auth0_client"
require "webmock"
require "tempfile"
include WebMock::API
WebMock.enable!
stub_request(:post, "https://example.auth0.com/oauth/token")
.to_return(status: 200, body: { access_token: "t", expires_in: 86_400 }.to_json,
headers: { "Content-Type" => "application/json" })
stub_request(:post, "https://example.auth0.com/api/v2/jobs/users-imports")
.to_return(status: 429, body: { statusCode: 429 }.to_json,
headers: { "Content-Type" => "application/json" })
client = Auth0Client.new(client_id: "id", client_secret: "secret", domain: "example.auth0.com")
file = Tempfile.new("users")
file.write('[{"email":"[email protected]"}]')
file.rewind
client.jobs.users_imports.create(users: file, connection_id: "con_123")
# => lib/auth0/internal/multipart/multipart_encoder.rb:68:in `write_part':
# Cannot write to closed encoder (RuntimeError)
With management_max_retries: 0 the same call raises Auth0::Errors::ClientError after one request, as expected.
Additional context
FormData#initializecreates the encoder once (lib/auth0/internal/multipart/multipart_form_data.rb:15) andFormData#encodereuses it (:63).Encoder#encodecloses it at the end.RawClient#sendbuilds the request body inside the retry loop (lib/auth0/internal/http/raw_client.rb:59), so every retry encodes the body again.- The
Content-Typeheader is built from the encoder's boundary inMultipart::Request#encode_headers, so a fix needs to keep the same boundary across attempts. For example, encode the body once per request and reuse the string, or letEncoder#encodereset its buffer instead of failing. - Like #800 / #811, this code lives under
lib/auth0/internal/, which is in.fernignore, so a regenerated release won't pick up a generator fix on its own. - Different from #796, which was about building the
userspart and is fixed in 6.5.0. - Our workaround for now: a separate client with
management_max_retries: 0for users imports, so a 429 surfaces asAuth0::Errors::ClientErrorand our background job retries it.
ruby-auth0 version
6.5.0
Ruby version
3.3.9
- Langage dominant
- Ruby
- Étoiles
- 205
- Forks
- 146
- Merge moyen
- 1 j 22 h
- PR mergées (30 j)
- 6
Préparer son environnement
- Aucun Dockerfile ni fichier Docker Compose
- Propose un modèle de pull request
- Lire le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de auth0/ruby-auth0
-
feature request
Difficulté 3/5 1-2 jours Accessibilité débutants 45/100
auth0/ruby-auth0#709 ·
Les mainteneurs répondent en général sous 1 jour
-
bug
Difficulté 1/5 Moins d'une heure Accessibilité débutants 50/100
auth0/ruby-auth0#610 · 1 commentaire ·
Les mainteneurs répondent en général sous 1 jour
-
Rate limit data returned from API methodsPeut-être pris Une pull request liée à cette issue est ouverte ou déjà fusionnée. Ouvertefeature request
Difficulté 5/5 Plus d'une semaine Accessibilité débutants 32/100
auth0/ruby-auth0#606 · 2 commentaires · 1 réaction ·
Les mainteneurs répondent en général sous 1 jour
-
MFA API Bearer token issuePeut-être pris Une pull request liée à cette issue est ouverte ou déjà fusionnée. Ouvertebug
Difficulté 3/5 1-2 jours Accessibilité débutants 35/100
auth0/ruby-auth0#556 · 2 commentaires ·
Les mainteneurs répondent en général sous 1 jour
-
feature request
Difficulté 3/5 1-2 jours Accessibilité débutants 35/100
auth0/ruby-auth0#500 · 1 commentaire ·
Les mainteneurs répondent en général sous 1 jour
Toutes les issues de auth0/ruby-auth0
Issues similaires
-
data error
Difficulté 2/5 1-3 heures Accessibilité débutants 74/100
riscv/riscv-unified-db#2794 ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 65/100
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 85/100
heartcombo/simple_form#1874 ·
-
Bug: Reports Monthly breakdown shows the whole first month when a custom range starts mid-monthOuverte
Difficulté 2/5 1-3 heures Accessibilité débutants 85/100
we-promise/sure#4603 ·
Les mainteneurs répondent en général sous 1 jour
-
Missing zh-CN translation: components/contributing:contributorsList.categorySwitcher.authoringOuverte
Difficulté 2/5 1-3 heures Accessibilité débutants 62/100
Les mainteneurs répondent en général sous 1 jour