- Item ID:
696102c94181b4eaba29f101 - Collection ID:
65e89895c5a4b8d764c0d895 - Slug:
learning-and-development-trends - Site ID:
65e89895c5a4b8d764c0d710 - Last successful publish:
2026-05-12T08:10:55.491Z
PR #109099 ("feat(custom-domains): add branch domain awareness to CustomDomainService") merged on May 19, expanding which publications are included in the allLive array during slug uniqueness validation. Before this PR, branch domain publications were not included. After it, they are.
Publication 69258a3f79dfa589c6408c34 (branch domain tts-widget-v2-0, created 2020, last updated July 2025) contains a different item (6841aa09d613692e33b5fd17) with the same slug learning-and-development-trends. This stale item was published to that branch domain before our log retention window and was previously invisible to slug validation.
- May 12: Item
696102c94181b4eaba29f101published successfully to all publications (branch domains not checked) - May 19: PR #109099 merges, branch domain publications now included in
allLive - May 21: First SIP failure, slug validation rejects self-update because stale item in branch domain publication is now visible
During SIP, validateItem at lines 274-300 builds the itemIdsBySlugAndLocale map from staging + ALL live publication databases in a single pass. With PR #109099, the old branch domain publication 69258a3f79dfa589c6408c34 is now included.
The map query finds:
696102c94181b4eaba29f101(from staging + 7 publication DBs)6841aa09d613692e33b5fd17(from the stale branch domain publication)
The set for key learning-and-development-trends_<localeId> now contains 2 item IDs. The validation at textField.ts:135 checks existingItemIds.size > 1 and throws immediately, before it reaches the has(docId) check at line 137. This happens during the FIRST publication's validation (which validates against ALL live DBs), so no publication gets written to, even the 7 that have the correct item ID.
// textField.ts:132-140
if (
existingItemIds &&
(existingItemIds.size > 1 || // <-- short-circuits here
!existingItemIds.has(String(docId))) // <-- never reached
) {
throw self._makeError('Unique value is already in database', value);
}The size > 1 check was introduced in PR #74887 (CMSAUTH-3411, Oct 2024) as a "robust slug uniqueness check." It's correct when all IDs in the set are from the same publication DB. But when the set aggregates across multiple publication DBs (as it does via allLive), a stale item in one publication poisons the check for all publications.
Remove the existingItemIds.size > 1 short-circuit and only check !existingItemIds.has(String(docId)):
// Before (current):
if (
existingItemIds &&
(existingItemIds.size > 1 ||
!existingItemIds.has(String(docId)))
) {
throw self._makeError('Unique value is already in database', value);
}
// After (proposed):
if (
existingItemIds &&
!existingItemIds.has(String(docId))
) {
throw self._makeError('Unique value is already in database', value);
}Rationale: If the current item's ID is in the set, it's a self-update and should be allowed regardless of how many other IDs exist. The size > 1 check was an optimization (fail fast) but is incorrect when the set contains IDs from multiple databases. Removing it doesn't weaken the validation: !has(docId) already catches the case where a different item owns the slug.
Edge cases: On insert, docId is undefined, so String(undefined) = "undefined" won't be in the set, and !has correctly rejects the duplicate. No behavior change for inserts.
Scope: Affects all slug uniqueness checks globally (SIP, CSV import, API).
Revert the effect of PR #109099 specifically for the SIP validation path, so branch domain publications are not included in the allLive array when building the itemIdsBySlugAndLocale map. This restores the pre-May-19 behavior where branch domains were invisible to slug validation.
Rationale: Branch domain publications may contain stale data from old publishes. Including them in slug validation introduces false positives for sites with long-lived branch domains. The slug uniqueness check was working correctly before branch domains were added to allLive.
Scope: Only affects the SIP path, not CSV import or API. Branch domains would still receive writes via writeToAllLive but wouldn't contribute to the pre-validation slug map.
The stale item in publication 69258a3f79dfa589c6408c34 needs to be resolved. Options:
- Republish the branch domain
branch--tts-widget-v2-0-synthesia-staging-eaff-03a8b1.webflow.io(full site publish to that target would reconcile the stale item) - Delete/unpublish the stale branch domain if it's no longer needed
| Environment | Publication ID | Item ID | Matches staging? | Admin Link |
|---|---|---|---|---|
| Staging | N/A | 696102c94181b4eaba29f101 |
-- | admin |
| Pub (checked) | 6a159632500787005df4ef69 |
696102c94181b4eaba29f101 |
YES | admin |
| Pub (checked) | 6a159d9b2f629a1884f72afd |
696102c94181b4eaba29f101 |
YES | admin |
| Pub (checked) | 6a05893a12d665a1493ce14f |
696102c94181b4eaba29f101 |
YES | admin |
| Pub (checked) | 69fb303c8a0016fc8c3dd4e8 |
696102c94181b4eaba29f101 |
YES | admin |
| Pub (MISMATCH) | 69258a3f79dfa589c6408c34 |
6841aa09d613692e33b5fd17 |
NO | admin |
| Pub (checked) | 69e241a56585e579e629fc76 |
696102c94181b4eaba29f101 |
YES | admin |
| Pub (checked) | 6a155e10b324501045b27b5c |
696102c94181b4eaba29f101 |
YES | admin |
| Pub (checked) | 6a158da297cf03e049b19b09 |
696102c94181b4eaba29f101 |
YES | admin |
| Pub (checked) | 6a159cee33ff32bf93ab28b7 |
not found | N/A | admin |
Publication 69258a3f79dfa589c6408c34 is the oldest (created 2020-05-27, last updated 2025-07-03) and has a different set of collections than the newer publications. The stale item 6841aa09d613692e33b5fd17 has zero logs in Datadog (even flex storage back to Jan 2026), so it predates the log retention window.
- Full trace (May 22, 202 with all pubs failed)
- Trace logs
- Fresh errors (May 27)
- All logs for this item (7d)
- Stale item search (no results)
| File | What |
|---|---|
entrypoints/server/routes/dynamo/v1/items.ts:848-908 |
PUT/PATCH /primary route handlers (fixed in PR #110150 to return 500) |
entrypoints/server/lib/logic/cms/items/updateLocalizedCMSItemsByPrimary.ts:305-357 |
attemptLocalizedItemUpdate catches errors and returns as data |
entrypoints/server/lib/logic/cms/internal/items/writeToAllLive.ts:88-276 |
Iterates publication DBs, per-pub validation |
entrypoints/server/lib/logic/cms/items/updateCMSItems.ts:387-414 |
validateItem input, skipLiveValidation: true, skipUniqueValidation |
entrypoints/server/lib/logic/cms/internal/items/validateItem.ts:274-300 |
Builds itemIdsBySlugAndLocale from staging + allLive |
entrypoints/server/lib/dynamo/schemaValidator/fields/textField.ts:118-141 |
Slug uniqueness check (existingItemIds.size > 1 short-circuits before has(docId)) |