{"record":{"id":"d5699dd39ed7361c","repo":"t8y2/dbx","slug":"validated-dynamodb-delete-key","errorCode":null,"errorMessage":"validated DynamoDB delete key","messagePattern":"validated DynamoDB delete key","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/dbx-core/src/db/dynamodb_driver.rs","lineNumber":388,"sourceCode":"        }\n        DynamoDbStatementOperation::Insert => {\n            let key = serde_json::to_string(statement.key.as_ref().expect(\"validated DynamoDB insert key\"))\n                .map_err(|error| error.to_string())?;\n            let item = serde_json::to_string(statement.item.as_ref().expect(\"validated DynamoDB insert item\"))\n                .map_err(|error| error.to_string())?;\n            insert_item_with_expected_identity(client, &statement.table, &item, Some(&key)).await?;\n            Ok(affected_query_result(1, started))\n        }\n        DynamoDbStatementOperation::Put => {\n            let key = serde_json::to_string(statement.key.as_ref().expect(\"validated DynamoDB put key\"))\n                .map_err(|error| error.to_string())?;\n            let item = serde_json::to_string(statement.item.as_ref().expect(\"validated DynamoDB put item\"))\n                .map_err(|error| error.to_string())?;\n            let affected = update_item(client, &statement.table, &key, &item).await?;\n            Ok(affected_query_result(affected, started))\n        }\n        DynamoDbStatementOperation::Delete => {\n            let key = serde_json::to_string(statement.key.as_ref().expect(\"validated DynamoDB delete key\"))\n                .map_err(|error| error.to_string())?;\n            let affected = delete_item(client, &statement.table, &key).await?;\n            Ok(affected_query_result(affected, started))\n        }\n    }\n}\n\nfn parse_dynamodb_statement(source: &str) -> Result<DynamoDbStatement, String> {\n    let mut lines = source.lines();\n    let header = lines\n        .find(|line| !line.trim().is_empty())\n        .map(str::trim)\n        .ok_or_else(|| \"DynamoDB statement is empty\".to_string())?;\n    let operation = match header.to_ascii_uppercase().as_str() {\n        \"DBX DYNAMODB SCAN\" | \"DBX DYNAMODB QUERY / SCAN\" => DynamoDbStatementOperation::Read,\n        \"DBX DYNAMODB INSERT ITEM\" => DynamoDbStatementOperation::Insert,\n        \"DBX DYNAMODB PUT ITEM\" => DynamoDbStatementOperation::Put,\n        \"DBX DYNAMODB DELETE ITEM\" => DynamoDbStatementOperation::Delete,","sourceCodeStart":370,"sourceCodeEnd":406,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/crates/dbx-core/src/db/dynamodb_driver.rs#L370-L406","documentation":"Panic from `Option::expect` on `statement.key` when serializing the key for a DynamoDB Delete statement. Deletes must target an explicit key guaranteed by validation; a None key reaching this code means the parser/validation step was bypassed and the process panics. This is an internal contract violation rather than a DynamoDB error.","triggerScenarios":"Calling execute_statement with DynamoDbStatementOperation::Delete and key = None — hand-built statements, externally supplied statement JSON that skipped validation, or a dropped validation branch.","commonSituations":"Programmatic delete construction; proxying user statements straight to the driver; incomplete test fixtures; refactors removing key validation for deletes.","solutions":["Create Delete statements only through parse_dynamodb_statement so key validation runs","Guard with statement.key.is_some() before executing a Delete","Replace expect with ok_or_else to return a recoverable 'delete requires a key' error","Add a unit test that a keyless Delete fails validation cleanly"],"exampleFix":"// before\nlet key = serde_json::to_string(statement.key.as_ref().expect(\"validated DynamoDB delete key\"))\n    .map_err(|error| error.to_string())?;\n// after\nlet key_src = statement.key.as_ref()\n    .ok_or_else(|| \"DynamoDB delete statement requires a key\".to_string())?;\nlet key = serde_json::to_string(key_src).map_err(|error| error.to_string())?;","handlingStrategy":"validation","validationCode":"if stmt.operation == DynamoDbStatementOperation::Delete && stmt.key.is_none() {\n    return Err(\"DynamoDB delete statement requires a key\".into());\n}","typeGuard":"fn is_deletable(stmt: &Statement) -> bool {\n    stmt.operation == DynamoDbStatementOperation::Delete && stmt.key.is_some()\n}","tryCatchPattern":"let affected = driver.execute_statement(stmt).await.map_err(|e| { eprintln!(\"delete failed: {e}\"); e })?;","preventionTips":["Never build Delete statements manually — use the parser","Validate key presence before destructive operations","Add a keyless-Delete test to your validation suite"],"tags":["rust","dynamodb","panic","invariant-violation"],"backgroundTag":"internal-invariant-panic","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}