Skip to content

Commit 7fb5b14

Browse files
Add pitfall: CommerceItem.categories is write-once (constructor only)
CommerceItem.categories can only be set through the constructor; assigning it afterward (natural to write via Kotlin .apply { }) compiles cleanly but throws at runtime on the first real purchase. A build-time check won't catch it, so it surfaces as a device crash inside the app's own trackPurchase wrapper — exactly the silent-until-runtime trap the skill exists to flag. Adds PITFALLS #21 with the correct constructor-arg form and a general rule to construct CommerceItem fully rather than mutate write-once fields after. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 2fad726 commit 7fb5b14

1 file changed

Lines changed: 32 additions & 0 deletions

File tree

iterable-android/PITFALLS.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,3 +322,35 @@ hot-path subset; the full list lives here and is loaded on demand.
322322
When a link opens the app but doesn't navigate, suspect a missing
323323
`customActionHandler` first — the dashboard template likely carries the link
324324
in the action *type* rather than as an `openUrl`.
325+
326+
## 21. Setting `CommerceItem.categories` after construction (compiles, crashes at runtime)
327+
328+
- **Symptom:** A green build, then a hard crash the first time a real purchase
329+
is reported — inside your own `trackPurchase` wrapper, not the SDK and not the
330+
checkout flow. Nothing surfaces until the code actually runs on a device.
331+
- **Cause:** `CommerceItem`'s `categories` is **write-once — settable only
332+
through the constructor**, not assignable afterward. Kotlin's `.apply { }`
333+
makes the wrong form look natural and it compiles cleanly:
334+
```kotlin
335+
// WRONG — compiles, throws at runtime on the assignment
336+
CommerceItem(id, name, price, quantity).apply {
337+
categories = arrayOf(product.category)
338+
}
339+
```
340+
The constraint is enforced only at runtime, so a build-time check (and the
341+
agent) won't catch it.
342+
- **Fix:** Pass `categories` (and the other optional fields) **in the
343+
constructor** — the SDK exposes a longer overload for exactly this. The
344+
positional order is `id, name, price, quantity, sku, description, url,
345+
imageUrl, categories` (categories last, as `Array<String>`):
346+
```kotlin
347+
CommerceItem(
348+
id, name, price, quantity,
349+
sku, description, url, imageUrl,
350+
arrayOf(product.category), // categories — set here, never reassigned
351+
)
352+
```
353+
General rule for this SDK: prefer constructing value objects like
354+
`CommerceItem` fully via their constructor rather than mutating fields
355+
post-construction with `.apply { }` — several fields are intentionally
356+
write-once and only enforce it at runtime.

0 commit comments

Comments
 (0)