alibaba/Sentinel · error · IllegalArgumentException

Bad file

Error message

Bad file

What it means

Thrown by the FileWritableDataSource constructor when the given File is null or is a directory. This writable data source serializes config back into a single file (e.g. for the Sentinel dashboard to persist rules), so a directory target is invalid.

Source

Thrown at sentinel-extension/sentinel-datasource-extension/src/main/java/com/alibaba/csp/sentinel/datasource/FileWritableDataSource.java:53

    private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

    private final Converter<T, String> configEncoder;
    private final File file;
    private final Charset charset;

    private final Lock lock = new ReentrantLock(true);

    public FileWritableDataSource(String filePath, Converter<T, String> configEncoder) {
        this(new File(filePath), configEncoder);
    }

    public FileWritableDataSource(File file, Converter<T, String> configEncoder) {
        this(file, configEncoder, DEFAULT_CHARSET);
    }

    public FileWritableDataSource(File file, Converter<T, String> configEncoder, Charset charset) {
        if (file == null || file.isDirectory()) {
            throw new IllegalArgumentException("Bad file");
        }
        if (configEncoder == null) {
            throw new IllegalArgumentException("Config encoder cannot be null");
        }
        if (charset == null) {
            throw new IllegalArgumentException("Charset cannot be null");
        }
        this.configEncoder = configEncoder;
        this.file = file;
        this.charset = charset;
    }

    @Override
    public void write(T value) throws Exception {
        lock.lock();
        try {
            String convertResult = configEncoder.convert(value);
            FileOutputStream outputStream = null;

View on GitHub (pinned to a3f40ba8e9)

Solutions

  1. Point the data source at a concrete file path ending in a file name (e.g. .../flow-rule.json).
  2. Assert the path is non-null before constructing; fail with the name of the missing property/config key.
  3. If the parent directory may not exist yet, create it with Files.createDirectories(parent) before writing (write() itself will fail otherwise).

Example fix

// before
new FileWritableDataSource<>("/opt/sentinel/rules/", encoder);

// after
Path p = Paths.get("/opt/sentinel/rules/flow-rule.json");
Files.createDirectories(p.getParent());
new FileWritableDataSource<>(p.toFile(), encoder);
Defensive patterns

Strategy: validation

Validate before calling

if (file == null || file.isDirectory()) {
    throw new IllegalArgumentException("writable rule path must be a file: " + path);
}
Files.createDirectories(file.toPath().getParent());
new FileWritableDataSource<>(file, encoder, charset);

Try / catch

try {
    writable = new FileWritableDataSource<>(file, encoder, charset);
} catch (IllegalArgumentException e) {
    throw new IllegalStateException("Invalid FileWritableDataSource config for path: " + path, e);
}

Prevention

When it happens

Trigger: new FileWritableDataSource(filePath, encoder) with a path that resolves to a directory; passing a null File after a failed path lookup; using the same directory path that works for a file-based reader without appending the file name.

Common situations: Configuring rule persistence with a path like /opt/sentinel/rules/ (directory) instead of /opt/sentinel/rules/flow-rule.json; path property typo; code that builds the File conditionally and passes null on the untested branch.

Related errors


AI-assisted analysis of alibaba/Sentinel@a3f40ba8e9 (2026-08-14). Data as JSON: /api/errors/066ca386454b5ba2. Report an issue: GitHub.