This has only started failing today and no code changes have been made to the SDK. My guess is a changed was made on your APIs to reject this.
Affected versions: confirmed in v6.0.2 and v7.1.0 (latest).
Environment: PHP 8.5, guzzlehttp/guzzle 7.x
Summary
MultiFactorAuth::challengeFactor() builds its request body with array_filter() over an all-optional payload. When the only field (sms_template) is omitted — the normal case for a TOTP factor — the body is an empty PHP array []. The SDK's HttpClient then passes it to Guzzle as 'json' => [], which json_encodes to the JSON array [] rather than an object {}. The WorkOS API rejects the non-object body with a 422 Unprocessable Entity (validation: "an unknown value was passed to the validate function").
Reproduction
$workos = new WorkOS\WorkOS(apiKey: $key, clientId: $clientId);
// TOTP factor → no sms_template
$workos->multiFactorAuth()->challengeFactor('auth_factor_...');
// → 422; request body on the wire is `[]`, not `{}`
Root cause
lib/Service/MultiFactorAuth.php (challengeFactor):
$body = array_filter(['sms_template' => $smsTemplate], fn ($v) => $v !== null); // [] when omitted
$this->client->request(method: 'POST', path: 'auth/factors/.../challenge', body: $body, ...);
lib/HttpClient.php (buildRequestOptions):
if ($body !== null) {
$requestOptions['json'] = $body; // [] → Guzzle encodes to `[]`
}
Guzzle's json option does not force object encoding, so an empty array serializes as []. This is a general problem for any endpoint whose body is entirely optional and fully omitted, not just challengeFactor.
Expected
The request body for a JSON-object endpoint should serialize as {} (or the endpoint should send no body), so the API accepts the call.
Suggested fix (any one)
- In
HttpClient, when a JSON body is an empty array, encode it as an object — e.g. send 'body' => '{}' with the JSON content-type, or json_encode($body, JSON_FORCE_OBJECT) for associative/empty payloads.
- In endpoints with all-optional bodies, cast to object:
body: (object) $body.
This has only started failing today and no code changes have been made to the SDK. My guess is a changed was made on your APIs to reject this.
Affected versions: confirmed in
v6.0.2andv7.1.0(latest).Environment: PHP 8.5,
guzzlehttp/guzzle7.xSummary
MultiFactorAuth::challengeFactor()builds its request body witharray_filter()over an all-optional payload. When the only field (sms_template) is omitted — the normal case for a TOTP factor — the body is an empty PHP array[]. The SDK'sHttpClientthen passes it to Guzzle as'json' => [], whichjson_encodes to the JSON array[]rather than an object{}. The WorkOS API rejects the non-object body with a422 Unprocessable Entity(validation: "an unknown value was passed to the validate function").Reproduction
Root cause
lib/Service/MultiFactorAuth.php(challengeFactor):lib/HttpClient.php(buildRequestOptions):Guzzle's
jsonoption does not force object encoding, so an empty array serializes as[]. This is a general problem for any endpoint whose body is entirely optional and fully omitted, not justchallengeFactor.Expected
The request body for a JSON-object endpoint should serialize as
{}(or the endpoint should send no body), so the API accepts the call.Suggested fix (any one)
HttpClient, when a JSON body is an empty array, encode it as an object — e.g. send'body' => '{}'with the JSON content-type, orjson_encode($body, JSON_FORCE_OBJECT)for associative/empty payloads.body: (object) $body.