{"record":{"id":"a96581c543da6dd7","repo":"apache/cassandra","slug":"failed-to-validate-a-hint-for-skipped","errorCode":null,"errorMessage":"Failed to validate a hint for {}: {} - skipped","messagePattern":"Failed to validate a hint for (.+?): (.+?) - skipped","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/java/org/apache/cassandra/hints/HintVerbHandler.java","lineNumber":82,"sourceCode":"        if (hint == null)\n        {\n            if (logger.isTraceEnabled())\n                logger.trace(\"Failed to decode and apply a hint for {}: {} - table with id {} is unknown\",\n                             address,\n                             hostId,\n                             message.payload.unknownTableID);\n            respond(message);\n            return;\n        }\n\n        // We must perform validation before applying the hint, and there is no other place to do it other than here.\n        try\n        {\n            hint.mutation.getPartitionUpdates().forEach(PartitionUpdate::validate);\n        }\n        catch (MarshalException e)\n        {\n            logger.warn(\"Failed to validate a hint for {}: {} - skipped\", address, hostId);\n            respond(message);\n            return;\n        }\n\n        ClusterMetadata metadata = ClusterMetadata.current();\n        NodeId localId = metadata.myNodeId();\n        if (!hostId.equals(localId.toUUID()) && !hostId.equals(metadata.directory.hostId(localId)))\n        {\n            // the hint may have been written prior to upgrading, in which case it would be addressing the old\n            // host id for its target node. If the id in the hint matches neither the pre-upgrade host id nor the\n            // post-upgrade node id for this peer, the node is not the final destination of the hint (must have gotten\n            // it from a decommissioning node), so just store it locally, to be delivered later.\n            HintsService.instance.write(hostId, hint);\n            respond(message);\n        }\n        else if (!StorageProxy.instance.appliesLocally(hint.mutation))\n        {\n            // the topology has changed, and we are no longer a replica of the mutation - since we don't know which node(s)","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/hints/HintVerbHandler.java#L64-L100","documentation":"When a hints message arrives, the handler validates that the hinted mutation's partition updates pass schema validation. If validation raises a MarshalException (e.g. the data no longer matches the local schema), the hint is considered invalid: it is logged with this warning, the sender is responded to as if delivered, and the hint is skipped rather than applied. This prevents corrupt or schema-incompatible hinted writes from failing the whole replay.","triggerScenarios":"A hint's mutation fails PartitionUpdate.validate() due to MarshalException — schema drift between sender and receiver, corrupted hint payload, or a table altered/dropped between hint creation and delivery.","commonSituations":"Schema changes (column type altered, table dropped) on the target node while hints were queued; mixing nodes with incompatible schema versions; corrupted hint files replayed after a crash.","solutions":["Run schema agreement (DESCRIBE SCHEMA diff) between source and target nodes and align schemas","Check which tableId/table the hint targets and whether the table was altered or dropped","If schema drift, run a repair/rebuild of the affected node instead of relying on hints","Verify all nodes run compatible Cassandra versions"],"exampleFix":"// before: altering a column type while hints pending\nALTER TABLE users ALTER age TYPE text;\n// after: drop and repopulate via repair instead, or drain hints first\nnodetool drain; -- then alter schema, then restart so hints are re-validated/created","handlingStrategy":"try-catch","validationCode":"// ensure schema agreement before relying on hinted handoff\n// on operator side:\n//   nodetool describecluster  -> check schema versions agree","typeGuard":null,"tryCatchPattern":"try {\n  hint.mutation.getPartitionUpdates().forEach(PartitionUpdate::validate);\n} catch (MarshalException e) {\n  logger.warn(\"Skipping invalid hint: {}\", e.getMessage());\n  respond(message); // treat as delivered, do not retry\n}","preventionTips":["Keep schema versions in agreement across the cluster before schema changes","Drain/flush hints before incompatible schema migrations","Run repairs after schema changes to backfill skipped hints","Keep node versions compatible"],"tags":["hints","validation","schema","marshal"],"backgroundTag":"schema-validation-failed","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}