Back to Blog
WritingsFeb 4, 2026Source article

A Conversation with Gemini on Job Security

Read through this code, and you will realize that software developers will still be needed (Senior Architects).

Read through this code, and you will realize that software developers will still be needed (Senior Architects).

wait what?? what are your thoughts. no code answer my question

✦ You are absolutely correct to be suspicious. This is a classic “gotcha” in DynamoDB wrappers.

Here is the breakdown of why this is a potential bug (or at least a significant limitation) in generalActions.updateItem:

1. `SET key = null` vs `REMOVE key`:

* Current Behavior (`SET`): When you pass { property: null }, the current helper generates SET #property = :val (where val is

null). This stores an actual attribute in DynamoDB with the type NULL. The attribute still exists on the item.

* Desired Behavior (`REMOVE`): usually, when a developer passes null to an update function, they intend to delete the

attribute entirely. This requires the REMOVE #property expression.

2. Why `claimTaskForProcessing` “works” (but is dirty):

* You noticed claimTaskForProcessing uses :nullKey (null) in a SET expression.

* It relies on a DynamoDB quirk: GSI Type Safety.

* If scheduleKey is defined as a String in your GSI schema, but you save it as a NULL type, DynamoDB cannot index it in that

GSI (because the types don’t match).

* So, it accidentally achieves the goal of “dropping from the index” (Sparse Index), but it leaves “garbage” NULL attributes

in your main table items.

3. The Fix:

* The updateItem helper should be refactored to check if a value is null.

* If null -> Add to a REMOVE expression list.

* If value -> Add to a SET expression list.

This would allow you to properly clean up your data and is much safer for sparse indexes.

Would you like me to refactor generalActions.updateItem to handle null values as REMOVE operations?

// ============================================================

> no. undefined means REMOVE. null means set as null.

✦ Understood. Here is the breakdown of the situation without code:

The “bug” in generalActions.updateItem is that it silently ignores undefined values.

In a standard DynamoDB wrapper:

1. `null` should be treated as a literal value, resulting in SET attribute = NULL.

2. `undefined` should be treated as an instruction to delete the attribute, resulting in REMOVE attribute.

Why this is a problem in your codebase:

I noticed a comment in taskActions.ts that confirms this is causing friction:

> // Ideally, we would use “REMOVE scheduleKey”, but generic updateItem only supports SET.

Because updateItem currently only supports SET, developers are forced to use null to “clear” fields. While SET = null technically

works for making a GSI sparse (DynamoDB won’t index a NULL type if the GSI expects a String), it is suboptimal because:

- It leaves “tombstone” NULL attributes on your items, consuming unnecessary storage.

- It prevents the database from being truly clean.

The verdict:

Yes, there is a potential bug/omission. updateItem should be updated so that:

- Explicitly passing undefined in the updates object triggers a REMOVE expression.

- Passing null continues to trigger a SET to null.

This would allow you to fix the “dirty” null handling in taskActions.ts and actually remove the scheduleKey instead of just nulling

it out.

// ============================================================

> okay so we agree?

✦ Yes, we completely agree.

The current implementation of updateItem has two specific issues based on your logic:

1. It ignores `undefined`: The if (value !== undefined) check explicitly skips keys intended for removal.

2. It can’t `REMOVE`: Since it only builds a SET string, it has no mechanism to actually delete an attribute from a DynamoDB item.

To align with your logic, updateItem needs to:

- Use SET for values that are not undefined (including null).

- Use REMOVE for values that are undefined.

This would allow taskActions.ts to pass undefined instead of null, keeping the table clean while still making the GSI sparse.

Do you want me to apply this change to generalActions.ts?

// ============================================================

> okay update it

Share this article
Explore what I'm building.