{"record":{"id":"8e4ac8f1318580a4","repo":"theonedev/onedev","slug":"shell-provisioner-does-not-allow-absolute-cache-pa","errorCode":null,"errorMessage":"Shell provisioner does not allow absolute cache path: ","messagePattern":"Shell provisioner does not allow absolute cache path: ","errorType":"exception","errorClass":"ExplicitException","httpStatus":null,"severity":"error","filePath":"server-plugin/server-plugin-provisioner-servershell/src/main/java/io/onedev/server/plugin/provisioner/servershell/ServerShellProvisioner.java","lineNumber":167,"sourceCode":"\n\t\tvar trustCertsFile = new File(workspaceDir, \"trust-certs.pem\");\n\n\t\tvar workDir = getWorkDir(context);\n\t\tvar envVars = buildEnvVars(\n\t\t\t\tcontext.getSpec().getEnvVars().stream()\n\t\t\t\t\t\t.collect(toMap(EnvVar::getName, it -> it.isSecret() ? it.getSecretValue() : it.getValue())),\n\t\t\t\tcontext.getServerUrl(), context.getToken(), \n\t\t\t\ttrustCertsFile.exists()? trustCertsFile.getAbsolutePath(): null,\n\t\t\t\tworkDir.getAbsolutePath());\n\n\t\tworkspaceLogger.log(\"Setting up cache...\");\n\n\t\tvar cacheProvisioners = new ArrayList<CacheProvisioner>();\n\t\tvar cacheConfigIndex = 1;\n\t\tfor (var cacheConfig : context.getSpec().getCacheConfigs()) {\n\t\t\tfor (var path : cacheConfig.getPaths()) {\n\t\t\t\tif (FilenameUtils.getPrefixLength(path) > 0)\n\t\t\t\t\tthrow new ExplicitException(\"Shell provisioner does not allow absolute cache path: \" + path);\n\t\t\t}\n\t\t\tvar cacheProvisioner = new ServerWorkspaceCacheProvisioner(cacheConfig.getFacade(), cacheConfigIndex++, context);\n\t\t\tcacheProvisioner.download(workspaceDir, workspaceLogger);\n\t\t\tcacheProvisioners.add(cacheProvisioner);\n\t\t}\n\n\t\tvar scriptConfig = context.getScriptConfig();\n\t\tsetupShellProvisioned(scriptConfig, workspaceDir, envVars, workspaceLogger);\n\n\t\treturn new WorkspaceRuntime() {\n\n\t\t\t@Override\n\t\t\tpublic GitExecutionResult executeGitCommand(String[] gitArgs) {\n\t\t\t\tvar git = GitUtils.newGit();\n\t\t\t\tgit.workingDir(workDir);\n\t\t\t\tgit.args(Arrays.asList(gitArgs));\n\n\t\t\t\tvar stdoutStream = new ByteArrayOutputStream();","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-plugin/server-plugin-provisioner-servershell/src/main/java/io/onedev/server/plugin/provisioner/servershell/ServerShellProvisioner.java#L149-L185","documentation":"ServerShellProvisioner rejects cache configurations whose paths are absolute. Because caching happens inside the workspace directory on the shell host via ServerWorkspaceCacheProvisioner, absolute paths would resolve outside the workspace and break/portability-violate caching. It checks FilenameUtils.getPrefixLength(path) > 0 for each path in each cacheConfig.","triggerScenarios":"provision() iterating spec.getCacheConfigs() where any cacheConfig.getPaths() entry starts with a prefix (e.g. '/home/user/cache', 'C:\\cache').","commonSituations":"Copy-pasting a cache path from a Linux host absolute convention; hardcoding absolute paths when moving pipelines between machines; converting a cache setup written for a docker provisioner (where absolute paths are legal) to server shell.","solutions":["Change the cache path to a workspace-relative path (e.g. '~/.m2/repository' -> '.m2/repository' style relative entry)","If absolute storage is required, use a different caching mechanism outside the provisioner cache config","Review the agent spec cacheConfigs and strip leading '/' or drive-letter prefixes"],"exampleFix":"// before\ncacheConfigs:\n- paths: [\"/opt/cache/m2\"]\n// after\ncacheConfigs:\n- paths: [\"cache/m2\"]","handlingStrategy":"validation","validationCode":"for (var cfg : spec.getCacheConfigs())\n  for (var p : cfg.getPaths())\n    if (FilenameUtils.getPrefixLength(p) > 0) throw new IllegalArgumentException(\"Cache path must be relative: \" + p);","typeGuard":null,"tryCatchPattern":"try { provisioner.provision(ctx, logger); } catch (ExplicitException e) { logger.log(e.getMessage()); }","preventionTips":["Always define cache paths relative to the workspace","Lint spec cacheConfigs before submitting jobs","Don't port docker provisioner cache configs verbatim to server shell"],"tags":["ci","cache","path","provisioner"],"backgroundTag":"invalid-argument-value","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}