Fix mailing list member vars encoding: {} for empty, normalize vars in createMultiple() - #961
Open
cheesegrits wants to merge 2 commits into
Open
cheesegrits wants to merge 2 commits into
cheesegrits wants to merge 2 commits into
Conversation
Member::create() always sends a `vars` form field, json_encode'd from its
$vars argument, and Member::update() does the same when given an array.
For the empty default that produces `[]`, a JSON array, where the API
requires a JSON object. Since 2026-09-25 the API rejects it:
400 The parameters passed to the API were invalid. Check your inputs!
'vars' parameter is not a valid JSON
so every create() call that did not pass vars started failing. Verified
against the live API: `vars={}` and omitting vars are both accepted,
`vars=[]` is rejected.
Both methods now route vars through encodeVars(), which emits `{}` for an
empty array and json_encode otherwise. testCreate pins the new shape,
testCreateWithVars and testUpdateEmptyVars cover the non-empty and the
update paths.
createMultiple() iterated $members by value, so its per-member handling
of `vars` (json_encode of an array) modified a copy and never reached
the request. In practice array vars already landed as nested JSON
objects, which is what the API wants, but two shapes went out wrong:
- an empty array encoded as `[]`, which the API rejects
("'vars' parameter is not a valid JSON", see the previous commit);
- a pre-encoded JSON string was nested as a JSON string, and the API
silently skips such a member while answering 200 (verified against
the live API: the member is never added).
The loop is now by reference and vars are normalized in place: an empty
array becomes an empty object so it encodes as `{}`, a pre-encoded JSON
object string is decoded so it lands as an object, and a string that is
not a JSON object throws InvalidArgumentException instead of being
dropped silently. Non-empty array vars behave exactly as before.
Author
|
The PHP-Compatibility failure is unrelated to this change: a new PHPCompatibility sniff flags trim() without an explicit characters argument (PHP 8.6 default change) in src/Api/Route.php and src/Message/MessageBuilder.php, neither touched here. All other checks pass. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two fixes to how
MailingList\Memberencodes a member'svars. The API requiresvarsto be a JSON object; both bugs sent something else.1.
create()andupdate()sent[]for an empty vars array.create()always includes avarsform field, json_encoded from its$varsargument, and the empty default encodes to[], a JSON array. Since 2026-09-25 the API rejects that:so every
create()call that did not pass vars started failing.update()did the same when handed an empty array. Both now send{}for an empty array (verified against the live API:vars={}and omitting vars are accepted,vars=[]is rejected).This looks like a change in the API's server-side validation rather than anything in the SDK: our application has run this exact
create()call, on this SDK version and its predecessors, for years without a single such error, and the first rejection appeared on 2026-09-25 at about 12:04 UTC with no deploy or dependency change on our side. The status page shows nothing for that day. Whether the array form was ever documented as valid or was merely tolerated,{}is what the API accepts now.2.
createMultiple()never normalized vars. Its per-member loop iterates$membersby value, so the innerjson_encodeof a vars array modified a copy and never reached the payload. Array vars therefore already landed as nested objects, but an empty array went out as[](rejected as above) and a pre-encoded JSON string was nested as a JSON string, which the API silently skips while answering 200 (verified live: the member is never added). The loop is now by reference and vars are normalized in place: an empty array encodes as{}, a pre-encoded JSON object string is decoded so it lands as an object, and a string that is not a JSON object throwsInvalidArgumentExceptioninstead of being dropped silently.Tests
testCreatenow pinsvars={}for the empty default (it previously pinned the rejected[]).testCreateWithVars,testUpdateEmptyVars: the non-empty and update paths.testCreateMultipleVarsStayJsonObjects: array, empty array and pre-encoded string vars all land as objects in the members JSON.testCreateMultipleInvalidVarsString: a non-JSON string throws.Workaround
If you are hitting
'vars' parameter is not a valid JSONonmember()->create()and need a fix before this is merged and released, either of these works on the current release with no SDK change:$varsarray, for example['source' => 'app']. It encodes to a JSON object, which the API accepts. The downside is that the value is stored on the member.createMultiple()with a one-element array instead:This sends no
varsat all. Do not pass'vars' => '{}'there on the current release: it is nested as a JSON string and the API silently skips the member (see bug 2).Notes
Existing callers passing
varsas a pre-encoded string tocreateMultiple()were never actually adding those members, so decoding the string is a behaviour fix rather than a break. Callers passing non-empty arrays anywhere see no change.