t8y2/dbx · info
checked above
Error message
checked above
What it means
Panic from `Option::expect` in validate_item_keys after `item.contains_key(&key.name)` returned true; the subsequent item.get(&key.name) is therefore guaranteed Some. The expect documents that get must succeed right after contains_key on the same map. It can only panic if the map is mutated between the two calls or the code is restructured without preserving the guard, or if the borrowed key/name disagree (same &str source, so not realistic).
Source
Thrown at crates/dbx-core/src/db/dynamodb_driver.rs:1198
.await
.map_err(|error| dynamodb_sdk_error!("Failed to delete DynamoDB item", error))?;
Ok(1)
}
fn json_document_to_item(doc_json: &str) -> Result<HashMap<String, AttributeValue>, String> {
let mut value: Value =
serde_json::from_str(doc_json).map_err(|error| format!("Invalid DynamoDB item JSON: {error}"))?;
let object = value.as_object_mut().ok_or_else(|| "DynamoDB item must be a JSON object".to_string())?;
object.remove("_id");
object.iter().map(|(key, value)| Ok((key.clone(), json_to_attribute_value(value)?))).collect()
}
fn validate_item_keys(table: &DynamoDbTableDescription, item: &HashMap<String, AttributeValue>) -> Result<(), String> {
for key in [Some(&table.partition_key), table.sort_key.as_ref()].into_iter().flatten() {
if !item.contains_key(&key.name) {
return Err(format!("DynamoDB item requires key attribute: {}", key.name));
}
let value = item.get(&key.name).expect("checked above");
let actual_type = match value {
AttributeValue::S(_) => "S",
AttributeValue::N(_) => "N",
AttributeValue::B(_) => "B",
_ => "non-scalar",
};
if actual_type != key.attribute_type {
return Err(format!(
"DynamoDB key attribute {} must use type {} (received {actual_type})",
key.name, key.attribute_type
));
}
}
Ok(())
}
fn item_key(
table: &DynamoDbTableDescription,View on GitHub (pinned to c0390bff16)
Solutions
- Keep contains_key immediately before get on the same unshared map
- Collapse to entry()/get + match to eliminate the expect: match item.get(&key.name) { Some(v) => ..., None => return Err(...) }
- Use item.get(&key.name).ok_or_else(|| ...)? to merge the check and retrieval
- Document the adjacency invariant with a comment or test
Example fix
// before
if !item.contains_key(&key.name) { return Err(...); }
let value = item.get(&key.name).expect("checked above");
// after
let Some(value) = item.get(&key.name) else {
return Err(format!("DynamoDB item requires key attribute: {}", key.name));
}; Defensive patterns
Strategy: validation
Validate before calling
for key_name in required_key_names(table) {
if !item.contains_key(key_name) {
return Err(format!("item missing key attribute: {key_name}"));
}
} Type guard
fn has_all_key_attributes(desc: &DynamoDbTableDescription, item: &HashMap<String, AttributeValue>) -> bool {
[Some(&desc.partition_key), desc.sort_key.as_ref()].into_iter().flatten()
.all(|k| item.contains_key(&k.name))
} Try / catch
match put_item_with_identity(client, table, &item).await {
Ok(_) => (),
Err(e) => eprintln!("item rejected: {e}"),
} Prevention
- Fetch the table description first and include every key attribute in items
- Match key attribute types (S/N/B) to the table's declared key types
- Validate items against the table schema before writes
When it happens
Trigger: Effectively unreachable as written; would fire only under concurrent mutation of the item map between contains_key and get, or if the contains_key guard is removed in a refactor.
Common situations: Code review refactors splitting the check and the get; concurrent writers to the item HashMap; not triggerable by normal API input.
Related errors
- checked length
- a batch cancellation token is always available
- driver token registered
- a cancellation token is always available
- checked one driver
AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05).
Data as JSON: /api/errors/2f0e39dacb49629a.
Report an issue: GitHub.