{"record":{"id":"cd460812955e9839","repo":"questdb/questdb","slug":"configuration-value-for-propertykey-cairo-sql-co","errorCode":null,"errorMessage":"Configuration value for ${PropertyKey.CAIRO_SQL_COPY_WORK_ROOT.propertyPath} can't point to root, data, conf or snapshot dirs.","messagePattern":"Configuration value for (.+?) can't point to root, data, conf or snapshot dirs\\.","errorType":"validation","errorClass":"ServerConfigurationException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/io/questdb/PropServerConfiguration.java","lineNumber":1028,"sourceCode":"\n        String configuredCairoSqlCopyRoot = getString(properties, env, PropertyKey.CAIRO_SQL_COPY_ROOT, \"import\");\n        if (!Chars.empty(configuredCairoSqlCopyRoot)) {\n            if (new File(configuredCairoSqlCopyRoot).isAbsolute()) {\n                this.cairoSqlCopyRoot = configuredCairoSqlCopyRoot;\n            } else {\n                if (absDbDir) {\n                    this.cairoSqlCopyRoot = rootSubdir(this.dbRoot, configuredCairoSqlCopyRoot); // ../import\n                } else {\n                    this.cairoSqlCopyRoot = new File(installRoot, configuredCairoSqlCopyRoot).getAbsolutePath();\n                }\n            }\n            String cairoSqlCopyWorkRoot = getString(properties, env, PropertyKey.CAIRO_SQL_COPY_WORK_ROOT, tmpRoot);\n            this.cairoSqlCopyWorkRoot = getCanonicalPath(cairoSqlCopyWorkRoot);\n            if (pathEquals(installRoot, this.cairoSqlCopyWorkRoot)\n                    || pathEquals(this.dbRoot, this.cairoSqlCopyWorkRoot)\n                    || pathEquals(this.confRoot, this.cairoSqlCopyWorkRoot)\n                    || pathEquals(this.checkpointRoot, this.cairoSqlCopyWorkRoot)) {\n                throw new ServerConfigurationException(\n                        \"Configuration value for \"\n                                + PropertyKey.CAIRO_SQL_COPY_WORK_ROOT.getPropertyPath()\n                                + \" can't point to root, data, conf or snapshot dirs.\"\n                );\n            }\n        } else {\n            this.cairoSqlCopyRoot = null;\n            this.cairoSqlCopyWorkRoot = null;\n        }\n\n        String configuredCairoSqlCopyExportRoot = getString(properties, env, PropertyKey.CAIRO_SQL_COPY_EXPORT_ROOT, \"export\");\n        if (!Chars.empty(configuredCairoSqlCopyExportRoot)) {\n            if (new File(configuredCairoSqlCopyExportRoot).isAbsolute()) {\n                this.cairoSqlCopyExportRoot = configuredCairoSqlCopyExportRoot;\n            } else {\n                if (absDbDir) {\n                    this.cairoSqlCopyExportRoot = rootSubdir(this.dbRoot, configuredCairoSqlCopyExportRoot); // ../export\n                } else {","sourceCodeStart":1010,"sourceCodeEnd":1046,"githubUrl":"https://github.com/questdb/questdb/blob/6610ab113b84528a73388b0722a38b97f9df78c2/core/src/main/java/io/questdb/PropServerConfiguration.java#L1010-L1046","documentation":"Thrown by PropServerConfiguration when cairo.sql.copy.work.root canonicalizes to the same path as the install root, db root, conf root, or checkpoint/snapshot root. QuestDB uses this directory as scratch space for COPY operations and rejects configurations that would make COPY work files collide with database or config directories.","triggerScenarios":"Setting cairo.sql.copy.work.root='.', '' resolving to the install root, the db directory, conf directory, or the snapshot dir in server.conf; also symlinks that canonicalize onto one of those roots (pathEquals compares canonical paths).","commonSituations":"Trying to keep copy work files 'tidy' by pointing them at the server root; env-var overrides in orchestration that accidentally set it to the data dir; migrating configs between versions where defaults changed.","solutions":["Point cairo.sql.copy.work.root at a dedicated scratch directory outside the install/db/conf/snapshot trees, e.g. /var/lib/questdb/copy-work or the default tmp root","If you intended the default, remove the property so it falls back to tmpRoot","Check for symlinks: the comparison uses canonical paths, so a link to the db root is also rejected"],"exampleFix":"# before\ncairo.sql.copy.work.root=/var/lib/questdb/db\n\n# after\ncairo.sql.copy.work.root=/var/lib/questdb/copy-work","handlingStrategy":"validation","validationCode":"Path work = Paths.get(props.getProperty(\"cairo.sql.copy.work.root\", tmpRoot)).toRealPath();\nList<Path> forbidden = List.of(installRoot, dbRoot, confRoot, checkpointRoot).stream()\n        .map(p -> { try { return p.toRealPath(); } catch (IOException e) { return p; } })\n        .toList();\nif (forbidden.contains(work)) {\n    throw new IllegalArgumentException(\"cairo.sql.copy.work.root collides with a protected dir: \" + work);\n}","typeGuard":null,"tryCatchPattern":"try {\n    new PropServerConfiguration(...);\n} catch (ServerConfigurationException e) {\n    // point the property at a dedicated scratch dir and restart\n}","preventionTips":["Give COPY work a dedicated directory on a fast local disk outside the install tree","Remember the check uses canonical paths, so symlinks to protected dirs are also rejected"],"tags":["configuration","server-conf","copy","filesystem"],"backgroundTag":null,"analyzedSha":"6610ab113b84528a73388b0722a38b97f9df78c2","analyzedAt":"2026-08-14T15:30:21.451Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}