astral-sh/ruff · error · io::Error

The system does not support writing files

Error message

The system does not support writing files

What it means

This is a Rust `std::io::Error` with `ErrorKind::Unsupported` produced by ty's `ProjectDatabase::writable_system()` when the underlying `System` does not implement the `WritableSystem` trait (`system().as_writable()` returns `None`). It surfaces when a caller (e.g. the ty server or `ty_python_semantic::fixes::fix_all`) attempts to write a file to disk, but the database was constructed with a read-only or virtual system that only supports reading. The library throws it to make write capability an explicit, checked property of the system abstraction instead of assuming writes always work.

Source

Thrown at crates/ty_project/src/db.rs:668

        ty_vendored::file_system()
    }

    fn system(&self) -> &dyn System {
        &*self.system
    }

    fn files(&self) -> &Files {
        &self.files
    }
}

#[salsa::db]
impl salsa::Database for ProjectDatabase {}

impl DbWithWritableSystem for ProjectDatabase {
    fn writable_system(&self) -> ruff_db::system::Result<&dyn WritableSystem> {
        self.system().as_writable().ok_or_else(|| {
            std::io::Error::new(
                std::io::ErrorKind::Unsupported,
                "The system does not support writing files",
            )
        })
    }
}

#[salsa::db]
impl Db for ProjectDatabase {
    fn project(&self) -> Project {
        self.project.unwrap()
    }

    fn uv_environments(&self) -> &UvEnvironments {
        &self.uv_environments
    }

    fn dyn_clone(&self) -> Box<dyn Db> {

View on GitHub (pinned to 15f3fe6b15)

Solutions

  1. Use a system that supports writing (e.g. `OsSystem`) when constructing the `ProjectDatabase` if you intend to write or apply fixes.
  2. If using a custom `System`, implement `as_writable()` to return a `Some(&dyn WritableSystem)` adapter (see `crates/ruff_db/src/system/os.rs:195`).
  3. Before calling write-dependent APIs (like `fix_all`), check writability up front via `db.system().as_writable().is_some()` and skip or surface a read-only message instead.
  4. If you only need analysis without writes, avoid invoking write paths so the read-only system is never asked to write.
  5. Keep the virtual/read-only system for tests but switch to `OsSystem` in production configuration.

Example fix

// before: read-only (virtual) system injected, writes fail
let system: DynSystem = test::TestSystem::new().into();
let db = ProjectDatabase::new(module_db, system);
fix_all(&mut db)?; // io::Error (Unsupported)

// after: use a writable OS-backed system
let system: DynSystem = OsSystem::new(cwd).into();
let db = ProjectDatabase::new(module_db, system);
fix_all(&mut db)?;
Defensive patterns

Strategy: validation

Validate before calling

// Check writability before calling write-dependent APIs
if db.system().as_writable().is_none() {
    eprintln!("Operation skipped: this system does not support writing files");
    return Ok(());
}

Type guard

fn is_writable(db: &dyn DbWithWritableSystem) -> bool {
    db.system().as_writable().is_some()
}

Try / catch

// Rust: match on the io::Error kind rather than any error
match db.writable_system() {
    Ok(system) => { /* use system to write */ }
    Err(e) if e.kind() == std::io::ErrorKind::Unsupported => {
        // read-only environment: degrade gracefully
        eprintln!("Cannot write: system is read-only");
    }
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: Calling any operation that goes through `DbWithWritableSystem::writable_system()` — such as applying code fixes (`fix_all`) that write files, or server write operations — while the `ProjectDatabase` was built over a system whose `as_writable()` returns `None` (e.g. the read-only test/memory system in `ruff_db::system::test`, or a custom read-only `System` implementation). The real `OsSystem` always returns `Some(self)`, so this only fires with non-OS systems.

Common situations: Running ty embedded in a tool or test harness that injects a virtual in-memory system for hermetic analysis; configuring the LSP server with a read-only system; implementing a custom `System` trait implementation without overriding `as_writable()` to return a writable adapter; calling fix/apply-diagnostics APIs in a read-only preview mode.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


AI-assisted analysis of astral-sh/ruff@15f3fe6b15 (2026-09-13). Data as JSON: /api/errors/2c9c78f3d1c1bc02. Report an issue: GitHub.