{"record":{"id":"359a6361e8a591ae","repo":"facebook/relay","slug":"localpersister-unable-to-read-the-file","errorCode":null,"errorMessage":"LocalPersister: Unable to read the {} file: {}","messagePattern":"LocalPersister: Unable to read the (.+?) file: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"compiler/crates/relay-compiler/src/operation_persister/local_persister.rs","lineNumber":47,"sourceCode":"/// This struct implements the `OperationPersister` trait, which defines the interface for persisting GraphQL operations.\npub struct LocalPersister {\n    /// The configuration for the local persister.\n    config: LocalPersistConfig,\n    /// A map of query IDs to query texts.\n    query_map: DashMap<String, String>,\n}\n\nimpl LocalPersister {\n    pub fn new(config: LocalPersistConfig) -> Self {\n        let query_map: DashMap<String, String> = match std::fs::read_to_string(&config.file) {\n            Ok(content) => serde_json::from_str(&content).unwrap_or_default(),\n            Err(e) if e.kind() == ErrorKind::NotFound => {\n                // First run: the file doesn't exist yet. Start with an empty\n                // map; `finalize` creates the file.\n                Default::default()\n            }\n            Err(e) => {\n                panic!(\n                    \"LocalPersister: Unable to read the {} file: {}\",\n                    config.file.display(),\n                    e,\n                )\n            }\n        };\n\n        Self { config, query_map }\n    }\n\n    fn hash_operation(&self, operation_text: String) -> String {\n        match self.config.algorithm {\n            LocalPersistAlgorithm::MD5 => {\n                let mut md5 = Md5::new();\n                md5.update(operation_text);\n                hex::encode(md5.finalize())\n            }\n            LocalPersistAlgorithm::SHA1 => {","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/facebook/relay/blob/668b1b85e06261aa3b58dabfc51f8b5524a70955/compiler/crates/relay-compiler/src/operation_persister/local_persister.rs#L29-L65","documentation":"LocalPersister::new reads the persisted-operations text file on startup. A NotFound error is treated as a first run (empty map), but any other read/parse-adjacent IO error (permissions, is-a-directory, IO failure) panics because the compiler cannot safely manage persisted operations without reading the existing state.","triggerScenarios":"Instantiating LocalPersister with a config.file path that exists but cannot be read: permission denied, path is a directory, or an IO error other than NotFound occurs while opening it.","commonSituations":"artifactDirectory owned by another user (e.g. created by Docker as root); the persisted-queries path accidentally set to a directory; read-only filesystem in CI.","solutions":["Fix permissions on the persisted operations file/directory (chmod/chown, especially for root-created Docker artifacts).","Ensure the configured path is a file, not a directory.","Delete the corrupt/unreadable file to re-initialize state (it is recreated on finalize).","Check the filesystem is writable/readable for the user running the compiler."],"exampleFix":"// before\npersistConfig: { file: __dirname + '/persisted' } // is a directory\n// after\npersistConfig: { file: __dirname + '/persisted/queries.json' }","handlingStrategy":"validation","validationCode":"const st = fs.statSync(persistFile);\nif (!st.isFile()) throw new Error('persist path must be a file');\nfs.accessSync(persistFile, fs.constants.R_OK | fs.constants.W_OK);","typeGuard":"function isReadableFile(p) { try { return fs.statSync(p).isFile() && fs.accessSync(p, fs.constants.R_OK) === undefined; } catch { return false; } }","tryCatchPattern":"try { startRelayPersist(config); } catch (e) { if (/LocalPersister: Unable to read/.test(String(e))) { fs.rmSync(persistFile, { force: true }); startRelayPersist(config); } else { throw e; } }","preventionTips":["Ensure the persisted-queries path is a file, not a directory","Fix ownership of artifact dirs created by Docker (run as same UID or chown)","Check filesystem writability in CI before running the compiler"],"tags":["filesystem","io","permissions","panic"],"backgroundTag":"file-read-permission-denied","analyzedSha":"668b1b85e06261aa3b58dabfc51f8b5524a70955","analyzedAt":"2026-09-02T19:57:20.783Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}