theonedev/onedev · error · UnauthorizedException

Not authorized to read code of project '${forkedFrom.path}'

Error message

Not authorized to read code of project '${forkedFrom.path}'

What it means

createProject throws UnauthorizedException when the request forks from a project (forkedFrom) whose code the subject cannot read. Forking copies build settings from the source project, so read-code access on it is mandatory.

Source

Thrown at server-core/src/main/java/io/onedev/server/rest/resource/ProjectResource.java:299

    @POST
    public Long createProject(@NotNull @Valid ProjectData data) {
		var project = new Project();
		data.populate(project, projectService);
		
		var subject = SecurityUtils.getSubject();
		var user = SecurityUtils.getUser(subject);

		checkProjectCreationPermission(subject, project.getParent());
	
		if (project.getParent() != null && project.isSelfOrAncestorOf(project.getParent())) 
			throw new NotAcceptableException("Cannot use current or descendant project as parent");
		
		checkProjectNameDuplication(project);		

		if (project.getForkedFrom() != null) {
			var forkedFrom = project.getForkedFrom();
			if (!SecurityUtils.canReadCode(subject, forkedFrom))
				throw new UnauthorizedException("Not authorized to read code of project '" + forkedFrom.getPath() + "'");
			project.getBuildSetting().setBuildPreservations(forkedFrom.getBuildSetting().getBuildPreservations());
			project.getBuildSetting().setCachePreserveDays(forkedFrom.getBuildSetting().getCachePreserveDays());
			project.getBuildSetting().setJobProperties(forkedFrom.getBuildSetting().getJobProperties());
			project.getBuildSetting().setDefaultFixedIssueFilters(forkedFrom.getBuildSetting().getDefaultFixedIssueFilters());
			project.getBuildSetting().setListParams(forkedFrom.getBuildSetting().getListParams(false));
			project.getBuildSetting().setNamedQueries(forkedFrom.getBuildSetting().getNamedQueries());
			project.setPackSetting(forkedFrom.getPackSetting());
			project.setPullRequestSetting(forkedFrom.getPullRequestSetting());
			project.setWorkspaceSetting(forkedFrom.getWorkspaceSetting());
			project.setNamedCommitQueries(forkedFrom.getNamedCommitQueries());
			project.setIssueSetting(forkedFrom.getIssueSetting());
			project.setNamedCodeCommentQueries(forkedFrom.getNamedCodeCommentQueries());
			projectService.create(user, project);
			projectService.fork(forkedFrom, project);
		} else {
			projectService.create(user, project);
		}

View on GitHub (pinned to d44925c47c)

Solutions

  1. Grant the account read-code permission on the fork source project (Project -> Access Control -> Code Read)
  2. Use a token of a user who can read the source project's code
  3. Remove forkedFrom if a plain (non-fork) project is intended
  4. Confirm the forkedFrom path/id refers to the intended project

Example fix

// before
POST /rest/projects {"name":"child","forkedFrom":{"path":"private/lib"}} // no code-read
// after: grant user code-read on private/lib, or drop the field
POST /rest/projects {"name":"child"}
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check code-read on fork source
const src = await api.get(`/rest/projects?path=${forkedFromPath}`);
if (!canReadCode(currentUser, src)) throw new Error('no code-read on ' + forkedFromPath);

Try / catch

try {
  await api.post('/rest/projects', payload);
} catch (e) {
  if (e.status === 401 && /read code/.test(e.message)) {
    // request code-read grant on the source project or drop forkedFrom
  } else throw e;
}

Prevention

When it happens

Trigger: POST /rest/projects with forkedFrom pointing at project '<path>' where SecurityUtils.canReadCode(subject, forkedFrom) is false — non-member, guest-only, or code-read permission not granted.

Common situations: Forking a private/team project using a personal token of a non-member; automation configured with a forkedFrom id from a different owner's project; group code-read permission removed after the automation was set up.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06). Data as JSON: /api/errors/e2edbf9a28de53e6. Report an issue: GitHub.