<WSProxyInstance>.resetClientIds
→ nullReset the Business Unit context previously set by setClientId — subsequent operations target the script's own BU again.
Runtime verified
Differs from official docs
Test scripts included
Syntax
<WSProxyInstance>.resetClientIds()
0 arguments
proxy.resetClientIds() clears any Business Unit context set by a previous proxy.setClientId() call. After resetting, all WSProxy operations target the BU the script is running in.
Parameters
None.
Show test script
<script runat="server">
/*
* Chapter: Parameters — "None."
*
* Proves:
* 1. resetClientIds is a CLR method on every WSProxy instance.
* 2. The documented 0-argument call form works (min_args = 0) and is
* safe even on a fresh proxy that never called setClientId.
* 3. NEGATIVE — passing one argument is rejected (max_args = 0).
* 4. NEGATIVE — passing two arguments is rejected (max_args = 0).
*
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function assertThrows(id, fn) {
var threw = false, msg = "";
try { fn(); } catch (ex) { threw = true; msg = "" + ex.message; }
Platform.Response.Write((threw ? "PASS " : "FAIL ") + id + " -> " + (threw ? "threw: " + msg : "did NOT throw") + "\n");
}
var proxy = new Script.Util.WSProxy();
/* 1. The method exists on the instance. */
assert("typeof proxy.resetClientIds is clrmethodinfo", typeof proxy.resetClientIds, "clrmethodinfo");
/* 2. The documented 0-argument form — no parameters at all. */
assert("resetClientIds() with no arguments is accepted (min_args = 0)", typeof proxy.resetClientIds(), "object");
var fresh = new Script.Util.WSProxy();
assert("resetClientIds() is safe on a fresh proxy that never called setClientId", (fresh.resetClientIds() === null) ? "true" : "false", "true");
/* 3. + 4. NEGATIVE — the method takes no parameters (max_args = 0). */
assertThrows("resetClientIds(arg) throws (max_args = 0)", function () { return proxy.resetClientIds({ ID: 123456 }); });
assertThrows("resetClientIds(arg1, arg2) throws (max_args = 0)", function () { return proxy.resetClientIds(1, 2); });
</script>
Return Value
null. Runtime-verified: resetClientIds() returns a genuine null value (=== null), not undefined.
Differs from official Salesforce docs
The official docs describe resetClientIds() as returning void, but at runtime it returns a genuine null (=== null), not undefined.
Show test script — null return, not void
<script runat="server">
/*
* Differs-from-docs claim: the official Salesforce docs describe
* resetClientIds() as returning void, but at runtime it returns a genuine
* null value, not undefined.
*
* Official docs: void (no value)
* SFMC runtime: null (=== null, typeof "object")
*
* Proves both halves of the claim:
* 1. DEV — the returned value strictly equals null (official docs: void,
* which in JS would surface as undefined).
* 2. DEV — the returned value does NOT strictly equal undefined, so a
* caller cannot treat it as a void return.
* 3. DEV — typeof the returned value is "object", the JS typeof of null,
* and not "undefined".
* 4. The distinction is observable: assigning the result to a variable
* yields a value whose `x == null` is true but `x === undefined` is
* false.
*
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
var proxy = new Script.Util.WSProxy();
/* 1.-3. The deviation itself. */
assert("DEV resetClientIds() === null (official docs: void)", (proxy.resetClientIds() === null) ? "true" : "false", "true");
assert("DEV resetClientIds() === undefined is false (official docs: void)", (proxy.resetClientIds() === undefined) ? "true" : "false", "false");
assert("DEV typeof resetClientIds() is object, not undefined (official docs: void)", typeof proxy.resetClientIds(), "object");
/* 4. The same distinction seen through a bound variable. */
var returned = proxy.resetClientIds();
assert("DEV the assigned return value is loosely null", (returned == null) ? "true" : "false", "true");
assert("DEV the assigned return value is strictly null", (returned === null) ? "true" : "false", "true");
assert("DEV the assigned return value is not strictly undefined", (returned === undefined) ? "true" : "false", "false");
</script>
Show test script
<script runat="server">
/*
* Chapter: Return Value — `null`
*
* Proves:
* 1. resetClientIds() returns a genuine null: `=== null` is true.
* 2. It is NOT undefined: `=== undefined` is false.
* 3. typeof the returned value is "object" — the JS typeof of null,
* not "undefined".
* 4. The same null is returned whether or not a setClientId call
* preceded it, so the return value is not a status signal.
*
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
var proxy = new Script.Util.WSProxy();
/* 1.-3. The documented return value. */
assert("resetClientIds() === null", (proxy.resetClientIds() === null) ? "true" : "false", "true");
assert("resetClientIds() !== undefined", (proxy.resetClientIds() === undefined) ? "true" : "false", "false");
assert("typeof resetClientIds() is object (the typeof of null)", typeof proxy.resetClientIds(), "object");
/* 4. Same null after an actual context switch. */
proxy.setClientId({ ID: 111111 });
assert("resetClientIds() === null after a preceding setClientId too", (proxy.resetClientIds() === null) ? "true" : "false", "true");
</script>
Examples
Switch BU, then reset
var proxy = new Script.Util.WSProxy();
// Target child BU
proxy.setClientId({ ID: 123456 });
var childResult = proxy.retrieve("DataExtension", ["Name", "CustomerKey"]);
// Restore own BU context before continuing
proxy.resetClientIds();
var ownResult = proxy.retrieve("DataExtension", ["Name", "CustomerKey"]);
Iterate over multiple BUs, then restore context
var proxy = new Script.Util.WSProxy();
var businessUnits = [
{ name: "US", mid: 111111 },
{ name: "EU", mid: 222222 }
];
for (var i = 0; i < businessUnits.length; i++) {
proxy.setClientId({ ID: businessUnits[i].mid });
var result = proxy.retrieve("DataExtension", ["Name"]);
Write(businessUnits[i].name + ": " + result.Results.length + " DEs<br>");
}
// Always reset after iterating to avoid unintended cross-BU side effects
proxy.resetClientIds();
Show test script
<script runat="server">
/*
* Chapter: Examples
*
* This CloudPage runs in a CHILD Business Unit (MCDEV_Training_QA), so a
* foreign MID is not accessible to it. That is exactly what makes the
* RESET observable: a setClientId to an inaccessible MID makes retrieve
* fail, and resetClientIds() restores a working own-BU context.
*
* Proves:
* 1. Example "Switch BU, then reset" — setClientId({ ID: <foreign MID> })
* is accepted, and the following retrieve is genuinely executed in
* that other BU context (it comes back Status "Error" naming the
* supplied ClientID, proving the context really moved).
* 2. resetClientIds() then restores the script's OWN BU: the next
* retrieve returns Status "OK" again.
* 3. Every row returned after the reset carries exactly one distinct
* Client.ID — the executing BU's own MID — proving "all WSProxy
* operations target the BU the script is running in".
* 4. Example "Iterate over multiple BUs, then restore context" — the
* documented loop over several MIDs runs without throwing, and the
* single resetClientIds() after the loop restores the own-BU context
* for the remainder of the script.
*
* NOT ASSERTED HERE (NOT ASSERTABLE from this harness): a SUCCESSFUL
* cross-BU retrieve, i.e. reading rows that belong to another Business
* Unit. This CloudPage runs in a child BU with no access to any other
* MID, so the happy path of the page examples (result.Results.length for
* a foreign BU) cannot be observed here. The reset itself — the subject
* of this page — is fully proven above via the Error -> OK transition.
*
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function assertContains(id, actual, fragment) {
var hay = "" + actual;
Platform.Response.Write((hay.indexOf(fragment) >= 0 ? "PASS " : "FAIL ") + id + " -> [" + hay + "]\n");
}
function assertNoThrow(id, fn) {
var threw = false, msg = "";
try { fn(); } catch (ex) { threw = true; msg = "" + ex.message; }
Platform.Response.Write((threw ? "FAIL " : "PASS ") + id + " -> " + (threw ? "threw: " + msg : "did not throw") + "\n");
}
var proxy = new Script.Util.WSProxy();
/* Baseline: the script's own BU, before any context switch. */
var before = proxy.retrieve("DataExtension", ["Name", "Client.ID"]);
assert("baseline retrieve in the own BU returns OK", "" + before.Status, "OK");
var ownMid = "" + before.Results[0].Client.ID;
/* 1. Example "Switch BU, then reset" — the switch half. */
assertNoThrow("setClientId({ ID: <foreign MID> }) is accepted", function () { return proxy.setClientId({ ID: 123456 }); });
var switched = proxy.retrieve("DataExtension", ["Name", "CustomerKey"]);
assertContains("the retrieve after setClientId ran in the SWITCHED context (denied for the supplied ClientID)", switched.Status, "123456");
/* 2. + 3. The reset half — own BU context is restored. */
assert("resetClientIds() returns null", (proxy.resetClientIds() === null) ? "true" : "false", "true");
var after = proxy.retrieve("DataExtension", ["Name", "Client.ID"]);
assert("the retrieve after resetClientIds() returns OK again", "" + after.Status, "OK");
assert("the retrieve after resetClientIds() returns rows", (after.Results.length > 0) ? "true" : "false", "true");
var seen = {};
var distinct = 0;
for (var i = 0; i < after.Results.length; i++) {
var mid = "" + after.Results[i].Client.ID;
if (!seen[mid]) { seen[mid] = 1; distinct = distinct + 1; }
}
assert("after the reset every row belongs to exactly one Business Unit", "" + distinct, "1");
assert("after the reset that Business Unit is the script's OWN BU", "" + after.Results[0].Client.ID, ownMid);
/* 4. Example "Iterate over multiple BUs, then restore context". */
var businessUnits = [
{ name: "US", mid: 111111 },
{ name: "EU", mid: 222222 }
];
var loopThrew = "false";
try {
for (var b = 0; b < businessUnits.length; b++) {
proxy.setClientId({ ID: businessUnits[b].mid });
proxy.retrieve("DataExtension", ["Name"]);
}
} catch (loopEx) {
loopThrew = "true";
}
assert("the documented multi-BU loop runs without throwing", loopThrew, "false");
assert("the single resetClientIds() after the loop returns null", (proxy.resetClientIds() === null) ? "true" : "false", "true");
var restored = proxy.retrieve("DataExtension", ["Name", "Client.ID"]);
assert("after the loop's reset, retrieve returns OK again", "" + restored.Status, "OK");
assert("after the loop's reset, rows come from the script's own BU", "" + restored.Results[0].Client.ID, ownMid);
</script>
Notes
Call resetClientIds() after finishing any cross-BU operations. Leaving the client ID set for the remainder of a script’s execution can cause later WSProxy calls to target the wrong BU.
Show test script
<script runat="server">
/*
* Chapter: Notes
*
* Proves the note "Leaving the client ID set for the remainder of a
* script's execution can cause later WSProxy calls to target the wrong
* BU":
* 1. A single setClientId affects the NEXT call — it is executed in the
* other BU context (Status "Error" naming the supplied ClientID).
* 2. The client ID PERSISTS: a second, entirely unrelated retrieve is
* still executed in that same wrong context without any further
* setClientId call.
* 3. It also leaks into a DIFFERENT object type — the context is per
* proxy instance, not per query.
* 4. Calling resetClientIds() after the cross-BU work — the note's
* recommendation — repairs the instance: the very next retrieve
* returns Status "OK" from the script's own BU.
* 5. The repair is durable: a further retrieve after the reset is still
* executed in the own BU.
*
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function assertContains(id, actual, fragment) {
var hay = "" + actual;
Platform.Response.Write((hay.indexOf(fragment) >= 0 ? "PASS " : "FAIL ") + id + " -> [" + hay + "]\n");
}
var proxy = new Script.Util.WSProxy();
var baseline = proxy.retrieve("DataExtension", ["Name", "Client.ID"]);
assert("baseline retrieve returns OK before any setClientId", "" + baseline.Status, "OK");
var ownMid = "" + baseline.Results[0].Client.ID;
/* 1. One setClientId moves the context. */
proxy.setClientId({ ID: 222222 });
var call1 = proxy.retrieve("DataExtension", ["Name"]);
assertContains("the call right after setClientId targets the other BU", call1.Status, "222222");
/* 2. The client ID is still set for the NEXT call — nothing was reset. */
var call2 = proxy.retrieve("DataExtension", ["CustomerKey"]);
assertContains("a later, unrelated call still targets the wrong BU (client ID persists)", call2.Status, "222222");
/* 3. And it leaks into other object types on the same instance. */
var call3 = proxy.retrieve("DataFolder", ["Name"]);
assertContains("the leaked context applies to a different object type too", call3.Status, "222222");
/* 4. The note's recommendation repairs the instance. */
assert("resetClientIds() after the cross-BU work returns null", (proxy.resetClientIds() === null) ? "true" : "false", "true");
var repaired = proxy.retrieve("DataExtension", ["Name", "Client.ID"]);
assert("the next retrieve after the reset returns OK", "" + repaired.Status, "OK");
assert("the next retrieve after the reset comes from the script's own BU", "" + repaired.Results[0].Client.ID, ownMid);
/* 5. The repair holds for subsequent calls too. */
var later = proxy.retrieve("DataExtension", ["Name", "Client.ID"]);
assert("a further retrieve after the reset is still in the own BU", "" + later.Results[0].Client.ID, ownMid);
assert("a further retrieve after the reset still returns OK", "" + later.Status, "OK");
</script>