{"record":{"id":"b2265df6a3f1e4ea","repo":"alibaba/canal","slug":"dir-path-can-not-read-write","errorCode":null,"errorMessage":"dir[{path}] can not read/write","messagePattern":"dir\\[(.+?)\\] can not read/write","errorType":"exception","errorClass":"CanalMetaManagerException","httpStatus":null,"severity":"error","filePath":"parse/src/main/java/com/alibaba/otter/canal/parse/index/FileMixedLogPositionManager.java","lineNumber":89,"sourceCode":"\n        this.executorService = Executors.newScheduledThreadPool(1);\n        this.persistTasks = Collections.synchronizedSet(new HashSet<>());\n    }\n\n    @Override\n    public void start() {\n        super.start();\n\n        if (!dataDir.exists()) {\n            try {\n                FileUtils.forceMkdir(dataDir);\n            } catch (IOException e) {\n                throw new CanalMetaManagerException(e);\n            }\n        }\n\n        if (!dataDir.canRead() || !dataDir.canWrite()) {\n            throw new CanalMetaManagerException(\"dir[\" + dataDir.getPath() + \"] can not read/write\");\n        }\n\n        if (!memoryLogPositionManager.isStart()) {\n            memoryLogPositionManager.start();\n        }\n\n        // 启动定时工作任务\n        executorService.scheduleAtFixedRate(() -> {\n            List<String> tasks = new ArrayList<>(persistTasks);\n            for (String destination : tasks) {\n                try {\n                    // 定时将内存中的最新值刷到file中，多次变更只刷一次\n                    flushDataToFile(destination);\n                    persistTasks.remove(destination);\n                } catch (Throwable e) {\n                    // ignore\n                    logger.error(\"period update\" + destination + \" curosr failed!\", e);\n                }","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/alibaba/canal/blob/87be50e87686a3e8af08c368d0e1ffd1f59eb04a/parse/src/main/java/com/alibaba/otter/canal/parse/index/FileMixedLogPositionManager.java#L71-L107","documentation":"During start(), FileMixedLogPositionManager ensures its data directory exists (creating it if needed) and then verifies it is both readable and writable. If either permission is missing it throws CanalMetaManagerException with the offending path. This is a runtime/environment check, not a constructor argument check.","triggerScenarios":"Calling start() when the dataDir exists (or was just created) but the canal process lacks read or write permission on it. Also triggered by a path that is a regular file rather than a directory, or an SELinux/AppArmor denial.","commonSituations":"Running the canal process as a different user than the directory owner; the data dir lives on a read-only mount; Docker volume mounted with wrong UID; directory owned by root but canal runs as non-root.","solutions":["Check ownership/permissions of the data directory and grant the canal process read+write (e.g. `chown` / `chmod 750` on the data dir).","Verify the dataDir path is a directory, not a file, and lives on a writable filesystem.","When running in a container, ensure the volume is mounted with the correct UID/GID matching the canal process."],"exampleFix":"// before\n// dataDir = /data/canal owned by root, canal runs as 'canal' user -> start() throws\n\n// after\n// sudo chown -R canal:canal /data/canal && sudo chmod 750 /data/canal\nmanager.start();","handlingStrategy":"validation","validationCode":"File dir = new File(Objects.requireNonNull(dataDirPath));\nif (!dir.exists() && !dir.mkdirs()) throw new IOException(\"cannot create \" + dir);\nif (!dir.canRead() || !dir.canWrite()) {\n    throw new IllegalStateException(\"dataDir not read/writeable: \" + dir);\n}\nmanager.start();","typeGuard":"boolean isReadWriteable(File f) {\n    return f != null && f.isDirectory() && f.canRead() && f.canWrite();\n}","tryCatchPattern":"try {\n    manager.start();\n} catch (CanalMetaManagerException e) {\n    // log the path, then surface a clear permission/ownership hint\n    logger.error(\"Cannot access dataDir; check permissions\", e);\n    throw e;\n}","preventionTips":["Pre-create the data directory and chown it to the canal process user.","In Docker, mount the data volume with the canal process UID/GID.","Run a startup probe that checks canRead/canWrite on the data dir before start()."],"tags":["canal","log-position-manager","filesystem","permissions","runtime"],"backgroundTag":null,"analyzedSha":"87be50e87686a3e8af08c368d0e1ffd1f59eb04a","analyzedAt":"2026-08-14T04:30:11.918Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}