{"record":{"id":"0a6173e5acfb54e8","repo":"apache/cassandra","slug":"snapshot-name-must-not-be-more-than-d-characters","errorCode":null,"errorMessage":"Snapshot name must not be more than %d characters long for resolved snapshot name (got %d characters for \"%s\")","messagePattern":"Snapshot name must not be more than (.+?) characters long for resolved snapshot name \\(got (.+?) characters for \"(.+?)\"\\)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/service/snapshot/SnapshotOptions.java","lineNumber":242,"sourceCode":"            {\n                throw new IllegalArgumentException(\"Snapshot name '\" + tag + \"' is reserved\");\n            }\n\n            if (!CassandraRelevantProperties.SNAPSHOT_NAME_VALIDATION.getBoolean())\n                return;\n\n            // Pre-generate snapshot name for the sake of the validation.\n            // getSnapshotName logic does not return raw \"tag\" as snapshot name every time,\n            // it e.g. prepends timestamp and type for system snapshots, and we need to validate it as a whole.\n            // If, for example, tag would be less than max allowed FILENAME_LENGTH,\n            // we might in fact produce a snapshot name longer than FILENAME_LENGTH if we prepended a timestamp to it.\n            String resolvedSnapshotName = SnapshotOptions.getSnapshotName(type, tag, now());\n\n            // the length of valid snapshot name has to be less than or equal to FILENAME_LEGTH - that is 255 -\n            // we are following the max length as it is in SchemaConstants for table name.\n            if (resolvedSnapshotName.length() > SchemaConstants.FILENAME_LENGTH)\n            {\n                throw new IllegalArgumentException(format(\"Snapshot name must not be more than %d characters long for \" +\n                                                          \"resolved snapshot name (got %d characters for \\\"%s\\\")\",\n                                                          FILENAME_LENGTH, resolvedSnapshotName.length(), resolvedSnapshotName));\n            }\n\n            // Allowed characters are a conservative subset of the AWS S3 \"Safe characters\" set\n            // (https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html#object-key-guidelines):\n            //   0-9  a-z  A-Z  -  _  .\n            // plus '+', which is not an S3 \"Safe character\" but can legitimately appear in system\n            // snapshot names via version build metadata (e.g. an upgrade snapshot \"<millis>-upgrade-5.0.4+build-...\").\n            // The remaining S3-safe characters (! * ' ( )) are intentionally excluded as they are\n            // shell-significant and error-prone in paths, and the path separator '/' is excluded too,\n            // which is what blocks traversal attempts such as \"../../mysnapshot\"\n            if (!SAFE_SNAPSHOT_NAME.matcher(resolvedSnapshotName).matches())\n            {\n                throw new IllegalArgumentException(\"Snapshot name contains illegal characters: \" + resolvedSnapshotName + \". \" +\n                                                   \"Allowed characters must match the pattern: \" + SAFE_SNAPSHOT_NAME.pattern() +\n                                                   \" with a maximum of length of \" + FILENAME_LENGTH + \" characters.\");\n            }","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/service/snapshot/SnapshotOptions.java#L224-L260","documentation":"When snapshot-name validation is enabled, the fully resolved snapshot name (built from snapshot type, tag, and timestamp) must fit the filesystem's FILENAME_LENGTH limit (255 chars, mirroring table-name limits). Over-long resolved names are rejected with the computed and actual lengths in the message.","triggerScenarios":"Supplying an excessively long tag such that type + tag + timestamp exceeds 255 characters in the resolved name; long keyspace/table-derived names combined with a long user tag.","commonSituations":"Generated tags embedding long hostnames, table lists, or ISO timestamps repeatedly; automated backup frameworks concatenating many labels into the tag.","solutions":["Shorten the snapshot tag so the resolved name fits within 255 characters.","Hash or truncate long identifiers before embedding them in the tag (e.g. SHA-256 prefix of the label).","Check length before calling: SnapshotOptions.getSnapshotName(type, tag, Instant.now()).length() <= SchemaConstants.FILENAME_LENGTH.","Keep tags short and put auxiliary metadata outside the snapshot name."],"exampleFix":"// before\nString tag = \"backup-\" + allTableNames; // >255 chars resolved\n// after\nString tag = \"backup-\" + DigestUtils.sha256Hex(allTableNames).substring(0, 12);","handlingStrategy":"validation","validationCode":"boolean fitsFilename(String type, String tag, Instant now) { return SnapshotOptions.getSnapshotName(type, tag, now).length() <= SchemaConstants.FILENAME_LENGTH; }","typeGuard":null,"tryCatchPattern":"try { options.build(); } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"characters long\")) { log.error(\"Shorten snapshot tag\"); } throw e; }","preventionTips":["Keep snapshot tags well under 200 characters","Truncate or hash long metadata embedded in tags","Pre-compute resolved names in automation to validate length before calling"],"tags":["snapshot","validation","illegalargument","filename-length"],"backgroundTag":"value-out-of-range","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T21:17:11.552Z"}