t8y2/dbx · error

validated DynamoDB put item

Error message

validated DynamoDB put item

What it means

Panic from `Option::expect` on `statement.item` when serializing the item for a DynamoDB Put statement. The validation layer must guarantee an item exists for Puts; a None here means an unvalidated statement reached the driver and the process aborts. It is an internal invariant failure, not a user-facing data error.

Source

Thrown at crates/dbx-core/src/db/dynamodb_driver.rs:382

                filter.as_deref(),
                sort.as_deref(),
                statement.cursor.as_deref(),
            )
            .await?;
            Ok(document_query_result(result, started))
        }
        DynamoDbStatementOperation::Insert => {
            let key = serde_json::to_string(statement.key.as_ref().expect("validated DynamoDB insert key"))
                .map_err(|error| error.to_string())?;
            let item = serde_json::to_string(statement.item.as_ref().expect("validated DynamoDB insert item"))
                .map_err(|error| error.to_string())?;
            insert_item_with_expected_identity(client, &statement.table, &item, Some(&key)).await?;
            Ok(affected_query_result(1, started))
        }
        DynamoDbStatementOperation::Put => {
            let key = serde_json::to_string(statement.key.as_ref().expect("validated DynamoDB put key"))
                .map_err(|error| error.to_string())?;
            let item = serde_json::to_string(statement.item.as_ref().expect("validated DynamoDB put item"))
                .map_err(|error| error.to_string())?;
            let affected = update_item(client, &statement.table, &key, &item).await?;
            Ok(affected_query_result(affected, started))
        }
        DynamoDbStatementOperation::Delete => {
            let key = serde_json::to_string(statement.key.as_ref().expect("validated DynamoDB delete key"))
                .map_err(|error| error.to_string())?;
            let affected = delete_item(client, &statement.table, &key).await?;
            Ok(affected_query_result(affected, started))
        }
    }
}

fn parse_dynamodb_statement(source: &str) -> Result<DynamoDbStatement, String> {
    let mut lines = source.lines();
    let header = lines
        .find(|line| !line.trim().is_empty())
        .map(str::trim)

View on GitHub (pinned to c0390bff16)

Solutions

  1. Always parse/validate Put statements via parse_dynamodb_statement before execution
  2. Verify statement.item.is_some() before calling execute_statement for Put
  3. Convert the expect into ok_or_else returning a clear error string
  4. Add a regression test for an itemless Put statement

Example fix

// before
let item = serde_json::to_string(statement.item.as_ref().expect("validated DynamoDB put item"))
    .map_err(|error| error.to_string())?;
// after
let item_src = statement.item.as_ref()
    .ok_or_else(|| "DynamoDB put statement requires an item".to_string())?;
let item = serde_json::to_string(item_src).map_err(|error| error.to_string())?;
Defensive patterns

Strategy: validation

Validate before calling

if stmt.operation == DynamoDbStatementOperation::Put && stmt.item.is_none() {
    return Err("DynamoDB put statement requires an item".into());
}

Type guard

fn has_dynamodb_item(stmt: &Statement) -> bool {
    stmt.item.is_some()
}

Try / catch

match driver.execute_statement(stmt).await {
    Ok(r) => r,
    Err(e) => { log::error!("put failed: {e}"); return Err(e); }
}

Prevention

When it happens

Trigger: Executing DynamoDbStatementOperation::Put with item = None, typically from statements assembled in code or deserialized without running parse_dynamodb_statement validation.

Common situations: Building put statements programmatically; forwarding raw user JSON to the driver; test fixtures without items; validation logic lost in refactors.

Related errors


AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05). Data as JSON: /api/errors/2eec1ec26fdfde2d. Report an issue: GitHub.