{"record":{"id":"8c1e76ed55a48705","repo":"apache/cassandra","slug":"snapshot-name-contains-illegal-characters-allow","errorCode":null,"errorMessage":"Snapshot name contains illegal characters: . Allowed characters must match the pattern:  with a maximum of length of  characters.","messagePattern":"Snapshot name contains illegal characters: \\. Allowed characters must match the pattern:  with a maximum of length of  characters\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/service/snapshot/SnapshotOptions.java","lineNumber":257,"sourceCode":"            // 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            }\n        }\n\n        private void validateTTL(boolean ephemeral, DurationSpec.IntSecondsBound ttl)\n        {\n            if (ttl != null)\n            {\n                int minAllowedTtlSecs = CassandraRelevantProperties.SNAPSHOT_MIN_ALLOWED_TTL_SECONDS.getInt();\n                if (ttl.toSeconds() < minAllowedTtlSecs)\n                    throw new IllegalArgumentException(format(\"ttl for snapshot must be at least %d seconds\", minAllowedTtlSecs));\n            }\n\n            if (ephemeral && ttl != null)\n                throw new IllegalStateException(format(\"can not take ephemeral snapshot (%s) while ttl is specified too\", tag));\n        }\n    }","sourceCodeStart":239,"sourceCodeEnd":275,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/service/snapshot/SnapshotOptions.java#L239-L275","documentation":"SnapshotOptions.validateTag rejects a snapshot (tag) name whose characters don't match the SAFE_SNAPSHOT_NAME pattern or which exceeds FILENAME_LENGTH. Cassandra restricts snapshot names to S3-safe, shell-friendly characters and blocks '/' so path traversal like '../../mysnapshot' cannot inject into snapshot directory paths. It throws IllegalArgumentException from build() before any snapshot is taken.","triggerScenarios":"Calling nodetool snapshot -t <tag> or TableMetadata/SnapshotOptions.builder().withTag(...) with a tag containing characters outside the allowed pattern (e.g. '/', '!', '*', quotes, spaces) or longer than FILENAME_LENGTH.","commonSituations":"Scripts embedding paths or timestamps with slashes into the tag; copy-pasted snapshot names with shell-significant chars; automation generating overly long tags from concatenated prefixes (e.g. upgrade snapshot names derived from version build metadata).","solutions":["Remove illegal characters from the snapshot name; use only characters allowed by SAFE_SNAPSHOT_NAME (alphanumerics, hyphen, underscore, dot) and stay under the max length.","Replace path-like tags with a flat name, e.g. 'daily-20260910' instead of 'daily/2026/09/10'.","If generating tags programmatically, sanitize/validate with the same regex before calling build()."],"exampleFix":"// before\nString tag = \"snapshots/2026/09/10\";\n// after\nString tag = \"snapshots-2026-09-10\";","handlingStrategy":"validation","validationCode":"Pattern SAFE = Pattern.compile(\"[a-zA-Z0-9][a-zA-Z0-9_\\\\-]*\");\nif (tag == null || tag.length() > 48 || !SAFE.matcher(tag).matches())\n    throw new IllegalArgumentException(\"Invalid snapshot tag: \" + tag);","typeGuard":null,"tryCatchPattern":"try { nodetoolSnapshot(tag); } catch (IllegalArgumentException e) { if (e.getMessage().contains(\"illegal characters\")) sanitizeAndRetry(tag); else throw e; }","preventionTips":["Whitelist-allow only [A-Za-z0-9_-] and dots in generated snapshot tags","Cap tag length well below FILENAME_LENGTH","Never build tags from paths or URLs"],"tags":["snapshot","validation","illegal-characters"],"backgroundTag":"invalid-identifier-format","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"}