facebook/relay · critical

Unable to canonicalize file {:?}. Error: {:?}

Error message

Unable to canonicalize file {:?}. Error: {:?}

What it means

normalize_path_from_config joins the config-relative path with the current directory and calls canonicalize; if the path does not exist or cannot be resolved (symlink loops, permissions), it panics with this message. The compiler requires every source path in relay.config to resolve to a real file/directory on disk.

Source

Thrown at compiler/crates/relay-compiler/src/config.rs:492

        self.sender.subscribe()
    }
}

impl Default for TestFileSourceConfig {
    fn default() -> Self {
        Self::new()
    }
}

fn normalize_path_from_config(
    current_dir: PathBuf,
    common_path: PathBuf,
    path_from_config: PathBuf,
) -> PathBuf {
    let mut src = current_dir.join(path_from_config.clone());

    src = canonicalize(src.clone())
        .unwrap_or_else(|err| panic!("Unable to canonicalize file {:?}. Error: {:?}", src, err));

    src.strip_prefix(common_path.clone())
        .unwrap_or_else(|_| {
            panic!(
                "Expect to be able to strip common_path from {:?} {:?}",
                src,
                common_path.clone(),
            );
        })
        .to_path_buf()
}

impl From<SingleProjectConfigFile> for Config {
    fn from(config: SingleProjectConfigFile) -> Self {
        Self::from_struct(
            "/virtual/path".into(),
            ConfigFile::SingleProject(config),
            false,

View on GitHub (pinned to 668b1b85e0)

Solutions

  1. Verify the path in your relay config exists relative to the config file location (ls it).
  2. Run the compiler from the project root where the config's relative paths are valid.
  3. Fix or remove broken symlinks and check read permissions on the path.
  4. If generated/moved dirs are the issue, update the config's path entries to the new location.

Example fix

// relay.config.js before
src: './srs', // typo
// after
src: './src',
Defensive patterns

Strategy: validation

Validate before calling

// before running the compiler
const src = path.resolve(configDir, cfg.src);
if (!fs.existsSync(src)) throw new Error(`relay src does not exist: ${src}`);

Type guard

function pathExists(p) { try { return fs.realpathSync(p) !== undefined; } catch { return false; } }

Prevention

When it happens

Trigger: Calling create_multi_project_config / ConfigFileProject with a src or path_from_config entry in the config that does not exist relative to the config's directory, or a path whose canonicalization fails (broken symlink, permission denied).

Common situations: Typo'd or moved src directory in relay.config.js; running the compiler from a different working directory than expected; broken symlink; running in a container where the source dir was not mounted.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of facebook/relay@668b1b85e0 (2026-09-02). Data as JSON: /api/errors/1c93928f1dae6678. Report an issue: GitHub.