Hacktoberfest 2026 : les issues que les mainteneurs ont marquées pour octobre, ouvertes et accessibles aux débutants. Parcourir les issues Hacktoberfest

Retrying a multipart request raises "Cannot write to closed encoder"

Ouverte
#818 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Les mainteneurs répondent en général sous 1 jour

@RaphaelFakhri y travaille déjà.

Depuis le 24/10/2026.

  • #819 par @RaphaelFakhri — ouverte

Évaluation

Difficulté
3/5
Temps estimé
1-2 jours
Accessibilité débutants
56/100
Type d'issue
Bug
Clarté
Clairement spécifiée
Activité
Active
Stack technique
ruby
Domaine
api, backend

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#initialize creates the encoder once (lib/auth0/internal/multipart/multipart_form_data.rb:15) and FormData#encode reuses it (:63). Encoder#encode closes it at the end.
  • RawClient#send builds the request body inside the retry loop (lib/auth0/internal/http/raw_client.rb:59), so every retry encodes the body again.
  • The Content-Type header is built from the encoder's boundary in Multipart::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 let Encoder#encode reset 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 users part and is fixed in 6.5.0.
  • Our workaround for now: a separate client with management_max_retries: 0 for users imports, so a 429 surfaces as Auth0::Errors::ClientError and 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

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de auth0/ruby-auth0

Toutes les issues de auth0/ruby-auth0

Issues similaires

Plus d'issues Ruby

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.