{"record":{"id":"638d3135fd5e0f34","repo":"theonedev/onedev","slug":"this-build-is-not-authorized-to-sync-to-project","errorCode":null,"errorMessage":"This build is not authorized to sync to project: ","messagePattern":"This build is not authorized to sync to project: ","errorType":"validation","errorClass":"ExplicitException","httpStatus":null,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/buildspec/step/PullRepository.java","lineNumber":161,"sourceCode":"\t\t\tProject project = build.getProject();\n\t\t\tProject targetProject;\n\t\t\tif (getTargetProject() != null) {\n\t\t\t\ttargetProject = getProjectService().findByPath(getTargetProject());\n\t\t\t\tif (targetProject == null)\n\t\t\t\t\tthrow new ExplicitException(\"Target project not found: \" + getTargetProject());\n\t\t\t} else {\n\t\t\t\ttargetProject = project;\n\t\t\t}\n\t\t\tboolean authorized = false;\n\t\t\tif (project.isCommitOnBranch(build.getCommitId(), project.getDefaultBranch()) \n\t\t\t\t\t&& project.isSelfOrAncestorOf(targetProject)) {\n\t\t\t\tauthorized = true;\n\t\t\t} else if (getAccessTokenSecret() != null && \n\t\t\t\t\tSecurityUtils.canManageProject(build.getAccessToken(getAccessTokenSecret()).asSubject(), targetProject)) {\n\t\t\t\tauthorized = true;\n\t\t\t}\n\t\t\tif (!authorized) \n\t\t\t\tthrow new ExplicitException(\"This build is not authorized to sync to project: \" + targetProject.getPath());\n\n\t\t\tLong userId;\n\t\t\tif (getAccessTokenSecret() != null) {\n\t\t\t\tuserId = build.getAccessToken(getAccessTokenSecret()).getOwner().getId();\n\t\t\t} else {\n\t\t\t\tuserId = User.SYSTEM_ID;\n\t\t\t}\n\n\t\t\tString remoteUrl = getRemoteUrlWithCredential(build);\n\t\t\tLong targetProjectId = targetProject.getId();\n\t\t\tvar task = new PullTask(targetProjectId, userId, remoteUrl, getCertificate(), getRefs(), isForce(), isWithLfs(), getProxy(), build.getSecretMasker());\n\t\t\tgetProjectService().runOnActiveServer(targetProjectId, task);\n\t\t\treturn new ServerStepResult(true);\n\t\t});\n\t}\n\t\n\tprivate static ProjectService getProjectService() {\n\t\treturn OneDev.getInstance(ProjectService.class);","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/buildspec/step/PullRepository.java#L143-L179","documentation":"PullRepositoryStep syncs a repository checkout into a target project during a build. Before doing so it verifies authorization: either the build's job token grants access, or an access token secret is set whose token owner can manage the target project. If neither check passes, an ExplicitException is thrown naming the target project path.","triggerScenarios":"Calling PullRepositoryStep.run when getAccessTokenSecret() is null and the build's job token does not authorize the target project, or when the access token's owner lacks manage permission (SecurityUtils.canManageProject false) on targetProject.","commonSituations":"Build spec references another project's repository without an access token secret configured; the access token belongs to a user who is not a project manager; job token scoping restricts the build to its own project; project was renamed/moved so the referenced path differs from what the token can access.","solutions":["Set the step's accessTokenSecret to a job secret holding an access token whose owner can manage the target project.","Grant the token owner 'Manage Project' permission on the target project in Project > Access Management.","If same-project sync, ensure the job token is permitted for that project (check job authorization settings).","Verify the target project path is correct and the project still exists."],"exampleFix":"// before\n- type: PullRepository\n  targetProjectPath: other/project\n// after\n- type: PullRepository\n  targetProjectPath: other/project\n  accessTokenSecret: cross-project-token","handlingStrategy":"validation","validationCode":"// Java: check authorization before adding PullRepositoryStep\nvar tokenOwner = build.getAccessToken(getAccessTokenSecret()).asSubject();\nif (getAccessTokenSecret() == null && !jobTokenAuthorized\n        || (getAccessTokenSecret() != null && !SecurityUtils.canManageProject(tokenOwner, targetProject))) {\n    throw new ExplicitException(\"Grant manage permission on \" + targetProject.getPath() + \" to the access token owner\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always define an access token secret for cross-project PullRepository steps.","Keep a dedicated service account with manage rights on all sync target projects.","Audit project paths after renames/moves."],"tags":["authorization","ci","build-spec","access-token"],"backgroundTag":"permission-denied","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}