Skip to content

Bulk user import broken in v3. Please regen with Fern ≥ 4.0.8 #855

@diutsu

Description

@diutsu

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

TL;DR the root cause is already fixed in Fern (fern-api/fern#14253, generator v4.0.8, merged 2026-03-27). auth0-java 3.4.0 (released 2026-04-09) still ships the buggy code.

Ask

Please regenerate with Fern ≥ 4.0.8 and release a 3.4.1 patch.

Issue

POST /api/v2/jobs/users-imports (bulk user import) is currently broken, preventing us from upgrading our SDK version from v2. In sum every call fails with an error related to the connection format:

ManagementApiException{message: BadRequestError, statusCode: 400, body: {
  "statusCode" : 400,
  "error" : "Bad Request",
  "message" : "Payload validation error: 'String does not match pattern ^con_[A-Za-z0-9]{16}$' on property connection_id.",
  "errorCode" : "invalid_body"
}}

Root cause. The Fern-generated RawUsersImportsClient.create(...) serializes String multipart field values through ObjectMappers.JSON_MAPPER.writeValueAsString(...), which JSON-encodes the string — "con_0123456789abcdef" with literal surrounding quotes — so Auth0's regex validator on the literal multipart body rejects it.

https://github.com/auth0/auth0-java/blob/v3.4.0/src/main/java/com/auth0/client/mgmt/jobs/RawUsersImportsClient.java#L70-L71

multipartBodyBuilder.addFormDataPart(
        "connection_id", ObjectMappers.JSON_MAPPER.writeValueAsString(request.getConnectionId()));

In the wire this looks like this:

--<boundary>
Content-Disposition: form-data; name="connection_id"

"con_0123456789abcdef"
--<boundary>
...

Only String-typed multipart fields are affected, because writeValueAsString(String) wraps the value in quotes.

Upstream fixed it

Fern merged fern-api/fern#14253 on 2026-03-27 — "fix(java): stop JSON-encoding multipart form string fields" — which addresses exactly this. From the PR description:

The Java SDK generator was wrapping all multipart form data fields in ObjectMappers.JSON_MAPPER.writeValueAsString(), which is correct for JSON request bodies but wrong for multipart form data. For string-typed fields, writeValueAsString("value") produces "\"value\"" (with embedded literal quotes), causing servers to receive malformed values.

The fix shipped in Fern generator v4.0.8. auth0-java 3.4.0 was released 13 days later (2026-04-09) but with buggy output, so the auto-regen PR must have run against an older pinned Fern version. A regenerate with v4.0.8 or newer should produce a correct RawUsersImportsClient.create(...) (and fix the same class of bug in any other Raw*Client that takes a String multipart field).

Reproduction

Standalone JUnit 5 test (requires com.auth0:auth0:3.4.0):

import com.auth0.client.mgmt.ManagementApi
import com.auth0.client.mgmt.core.ManagementApiException
import com.auth0.client.mgmt.jobs.types.CreateImportUsersRequestContent
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Assertions.fail
import org.junit.jupiter.api.Test
import java.nio.file.Files

class BulkImportReproTest {
    private val domain = "<AUTH0_DOMAIN>"                    // e.g. "dev-xyz.eu.auth0.com"
    private val clientId = "<AUTH0_CLIENT_ID>"
    private val clientSecret = "<AUTH0_CLIENT_SECRET>"
    private val connectionId = "<AUTH0_CONNECTION_ID>"       // real con_... 16 chars, M2M app has create:users

    @Test
    fun `createBulkUsers fails with 400 because connection_id is JSON-quoted`() {
        val api = ManagementApi.builder()
            .domain(domain)
            .clientCredentials(clientId, clientSecret)
            .audience("https://$domain/api/v2/")
            .build()

        val usersFile = Files.createTempFile("users-", ".json").toFile().apply { writeText("[]"); deleteOnExit() }

        try {
            api.jobs().usersImports().create(
                usersFile,
                CreateImportUsersRequestContent.builder()
                    .connectionId(connectionId)
                    .upsert(true)
                    .build(),
            )
            fail("Expected 400, got success — bug may have been fixed")
        } catch (e: ManagementApiException) {
            assertEquals(400, e.statusCode)
            val body = e.body.toString()
            assertTrue(body.contains("String does not match pattern") && body.contains("connection_id"))
        }
    }
}

Additional context

No response

auth0-java version

3.4.0

Java version

21

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugThis points to a verified bug in the code

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions