Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

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

未关闭
#818 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

@RaphaelFakhri 已经在做这个了。

开始于 2026年10月24日。

  • #819 来自 @RaphaelFakhri —— 未关闭

评估

难度
3/5
预计耗时
1-2 天
新手友好度
56/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
活跃
技术栈
ruby
领域
api, backend

调研方向

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.

由索引模型根据 Issue 内容生成。

描述

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

主要语言
Ruby
星标
205
派生
146
平均合并
1 天 15 小时
30 天内合并 PR
7

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

auth0/ruby-auth0 的其他 Issue

查看 auth0/ruby-auth0 的全部 Issue

相似的 Issue

更多 Ruby Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。