apache/cassandra · error · IllegalArgumentException
Invalid directory
Error message
Invalid directory {directory} What it means
bulkLoadInternal(directory) is the implementation behind `nodetool refresh`/bulk load APIs. It validates that the given path exists and is a directory; otherwise it throws IllegalArgumentException. The path is resolved on the Cassandra server host, not the client machine.
Solutions
- Verify the path on the node: it must exist and be a directory containing SSTable files (with -db, -TOC, etc. components)
- Run nodetool refresh on the correct host where the SSTables were placed (scp first if remote)
- Place SSTables under the table's upload directory or any directory the cassandra process can read
- Check container volume mappings if running Cassandra in Docker - the path must be visible inside the container
Example fix
// before: client-local path passed to remote node nodetool refresh ks tbl /local/tmp/sstables // after: copy files to the server, then refresh scp -r /local/tmp/sstables node:/var/lib/cassandra/data/ks/tbl-upload-ks-tbl-ks-tbl/ ssh node 'nodetool refresh ks tbl'
Defensive patterns
Strategy: validation
Validate before calling
File dir = new File(directory);
if (!dir.exists() || !dir.isDirectory())
throw new IllegalArgumentException("not a server-side directory: " + directory); Type guard
boolean isBulkLoadableDir(String path) {
File d = new File(path);
return d.exists() && d.isDirectory();
} Try / catch
try { ss.bulkLoad(directory); } catch (IllegalArgumentException e) { if (e.getMessage().startsWith("Invalid directory")) { log.error("path missing on server host: {}", directory); } throw e; } Prevention
- Remember bulkLoad/refresh paths resolve on the server, not the client
- Stage SSTables in the table's -upload directory before refresh
- Check that the cassandra OS user has read access to the directory
- Verify container volume mappings when running in Docker
When it happens
Trigger: Calling `nodetool refresh <keyspace> <cf>` or StorageService.bulkLoad(path) with a path that doesn't exist on the server, or that is a file rather than a directory of SSTables.
Common situations: Copying SSTables to the wrong host or a path the cassandra user can't see; passing a local path from a remote nodetool client; staging files under a truncated/renamed directory; docker/container path mismatch.
Related errors
- 3
- Exception occurred while writing to
- Failed importing SSTables
- Failed to list files in
- FSReadError (wraps IOException reading TOC file)
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/1dced608fd925a3e.
Report an issue: GitHub.
Appendix: source
Thrown at src/java/org/apache/cassandra/service/StorageService.java:4546
bulkLoadInternal(directory).get();
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}
public String bulkLoadAsync(String directory)
{
return bulkLoadInternal(directory).planId.toString();
}
private StreamResultFuture bulkLoadInternal(String directory)
{
File dir = new File(directory);
if (!dir.exists() || !dir.isDirectory())
throw new IllegalArgumentException("Invalid directory " + directory);
SSTableLoader.Client client = new SSTableLoader.Client()
{
private String keyspace;
public void init(String keyspace)
{
this.keyspace = keyspace;
try
{
for (Map.Entry<Range<Token>, EndpointsForRange> entry : getRangeToAddressMap(keyspace).entrySet())
{
Range<Token> range = entry.getKey();
EndpointsForRange replicas = entry.getValue();
Replicas.temporaryAssertFull(replicas);
for (InetAddressAndPort endpoint : replicas.endpoints())
addRangeForEndpoint(range, endpoint);
}View on GitHub (pinned to 88fd0f6a0e)