{"record":{"id":"463300de311137c9","repo":"t8y2/dbx","slug":"validated-dynamodb-insert-key","errorCode":null,"errorMessage":"validated DynamoDB insert key","messagePattern":"validated DynamoDB insert key","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/dbx-core/src/db/dynamodb_driver.rs","lineNumber":372,"sourceCode":"            let requested_limit = statement.limit.unwrap_or(max_rows.max(1).min(MAX_PAGE_SIZE as usize) as i64);\n            let effective_limit = requested_limit.min(max_rows.max(1).min(i64::MAX as usize) as i64);\n            let filter =\n                statement.filter.as_ref().map(serde_json::to_string).transpose().map_err(|error| error.to_string())?;\n            let sort =\n                statement.sort.as_ref().map(serde_json::to_string).transpose().map_err(|error| error.to_string())?;\n            let result = find_items(\n                client,\n                &statement.table,\n                effective_limit,\n                filter.as_deref(),\n                sort.as_deref(),\n                statement.cursor.as_deref(),\n            )\n            .await?;\n            Ok(document_query_result(result, started))\n        }\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?;","sourceCodeStart":354,"sourceCodeEnd":390,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/crates/dbx-core/src/db/dynamodb_driver.rs#L354-L390","documentation":"This is a Rust panic from `Option::expect` on `statement.key` when serializing the key for a DynamoDB Insert statement. The library assumes an earlier validation/parse step guaranteed a key exists for inserts; if it is None, the invariant is broken and the process panics instead of returning a typed error. It signals an internal contract violation between statement parsing/validation and execution, not a user-facing DynamoDB failure.","triggerScenarios":"Calling execute_statement with a DynamoDbStatementOperation::Insert whose `key` field is None — e.g. a hand-constructed Statement that bypasses parse_dynamodb_statement, or a code path that forgets to validate key presence for inserts (see rejects_write_statement_without_explicit_key).","commonSituations":"Building Statement structs programmatically instead of via the statement parser; a validation refactor dropping the insert-key check; deserializing statements from external input (JSON/API) without re-running validation.","solutions":["Always construct DynamoDB insert statements through parse_dynamodb_statement so the explicit-key validation runs before execute_statement","Before calling execute_statement for Insert, check statement.key.is_some() and return a proper error if absent","Replace the expect with .ok_or_else(|| \"DynamoDB insert requires a key\".to_string())? so the failure becomes a recoverable error","Add a regression test feeding a keyless Insert statement to execute_statement and asserting a clean error"],"exampleFix":"// before\nlet key = serde_json::to_string(statement.key.as_ref().expect(\"validated DynamoDB insert key\"))\n    .map_err(|error| error.to_string())?;\n// after\nlet key_src = statement.key.as_ref()\n    .ok_or_else(|| \"DynamoDB insert statement requires a key\".to_string())?;\nlet key = serde_json::to_string(key_src).map_err(|error| error.to_string())?;","handlingStrategy":"validation","validationCode":"if let Some(stmt) = statement.as_dynamodb_mut() {\n    if stmt.operation == DynamoDbStatementOperation::Insert && stmt.key.is_none() {\n        return Err(\"DynamoDB insert statement requires a key\".into());\n    }\n}","typeGuard":"fn has_dynamodb_key(stmt: &Statement) -> bool {\n    stmt.key.is_some()\n}","tryCatchPattern":"match driver.execute_statement(statement).await {\n    Ok(result) => result,\n    Err(e) => eprintln!(\"statement execution failed: {e}\"),\n    // panics are not catchable in normal flow — validate first\n}","preventionTips":["Build statements via the provided parser, never by hand","Assert key/item presence in tests for every write operation","Keep validation and execution in the same code path"],"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"}