facebook/relay · critical
Expect to be able to strip common_path from {:?} {:?}
Error message
Expect to be able to strip common_path from {:?} {:?} What it means
After canonicalizing the source path, normalize_path_from_config strips the shared common_path prefix so relative project paths can be computed. If the canonicalized src is not under common_path, stripping fails and the compiler panics, since its path model assumes all project sources live under the common root.
Source
Thrown at compiler/crates/relay-compiler/src/config.rs:496
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,
)
.unwrap()
}
}View on GitHub (pinned to 668b1b85e0)
Solutions
- Ensure each project's src is physically (post-symlink-resolution) inside the common root directory.
- Check symlink targets with realpath and point them inside the repo.
- Restructure multi-project config so all project directories share a common ancestor that the compiler computes as common_path.
- Avoid absolute paths pointing outside the project tree in the config.
Example fix
// before
src: path.resolve('/external/libs/ui'), // outside common root
// after
src: './packages/ui', Defensive patterns
Strategy: validation
Validate before calling
const canon = fs.realpathSync(path.resolve(cfg.src));
const common = fs.realpathSync(commonRoot);
if (!canon.startsWith(common + path.sep)) throw new Error(`src ${canon} is outside common root ${common}`); Type guard
function isUnderRoot(child, root) { const c = path.resolve(child), r = path.resolve(root); return c === r || c.startsWith(r + path.sep); } Prevention
- Resolve symlinks (realpath) before asserting project layout
- Keep all multi-project sources under one common ancestor
- Avoid absolute paths outside the repo in relay configs
When it happens
Trigger: create_multi_project_config with a project's src that canonicalizes to a location outside common_path — e.g. a symlink pointing outside the root, a src defined as an absolute path elsewhere, or overlapping project roots that don't share the computed prefix.
Common situations: Symlinked src directories resolving outside the repo; multi-project configs where one project's directory sits outside the common root; canonicalization turning ./a/../b into a path that escapes common_path.
Related errors
- Unable to canonicalize file {:?}. Error: {:?}
- Unable to get current working directory.
- Expected to have access to AST and docblock sources.
- LocalPersister: Unable to read the {} file: {}
- Expected the JS type for '{}' to be defined, please update '
AI-assisted analysis of facebook/relay@668b1b85e0 (2026-09-02).
Data as JSON: /api/errors/6ea0876a80485c99.
Report an issue: GitHub.