theonedev/onedev · error · UnauthorizedException

Not authorized

Error message

Not authorized

What it means

The mergePullRequest endpoint checks SecurityUtils.canWriteCode(user.asSubject(), pullRequest.getProject()); if the authenticated user lacks code write permission on the PR's project, an UnauthorizedException ('Not authorized') is thrown before the merge is performed.

Source

Thrown at server-core/src/main/java/io/onedev/server/ai/TodResource.java:1503

        return PullRequestHelper.getDetail(currentProject, pullRequest);        
    }

    @Path("/merge-pull-request")
    @Consumes(MediaType.TEXT_PLAIN)
    @POST
    public Map<String, Object> mergePullRequest(
                @QueryParam("currentProject") @NotNull String currentProjectPath,
                @QueryParam("reference") @NotNull String pullRequestReference,
                String commitMessage) {
        var user = SecurityUtils.getUser();
        if (user == null)
            throw new UnauthenticatedException();

        var currentProject = getProject(currentProjectPath);
        var pullRequest = getPullRequest(currentProject, pullRequestReference);

        if (!SecurityUtils.canWriteCode(user.asSubject(), pullRequest.getProject()))
            throw new UnauthorizedException();

        commitMessage = trimToNull(commitMessage);

        pullRequestService.merge(user, pullRequest, commitMessage);

        return PullRequestHelper.getDetail(currentProject, pullRequest);        
    }

    @Path("/discard-pull-request")
    @Consumes(MediaType.TEXT_PLAIN)
    @POST
    public Map<String, Object> discardPullRequest(
                @QueryParam("currentProject") @NotNull String currentProjectPath,
                @QueryParam("reference") @NotNull String pullRequestReference,
                String comment) {
        var user = SecurityUtils.getUser();
        if (user == null)
            throw new UnauthenticatedException();

View on GitHub (pinned to d44925c47c)

Solutions

  1. Grant the user or token's role code write permission on the PR's project in OneDev security settings.
  2. Use a token/account that has write access to the target project.
  3. Verify the correct project — permission is evaluated against the PR's own project, not currentProject.

Example fix

// before
// token user has only 'Read' role on project
mergePullRequest(ref)
// after
// Admin: Project -> Security -> give role 'Code Write', or use an account with write access
mergePullRequest(ref)
Defensive patterns

Strategy: validation

Validate before calling

const me = await getCurrentUser()
if (!canWriteCode(me, pr.project)) throw new Error(`user ${me.name} lacks code write permission on ${pr.project}`)

Type guard

function canMerge(user, project) { return Boolean(user?.permissions?.[project]?.includes('WRITE_CODE')) }

Try / catch

try { await mergePullRequest(ref) }
catch (e) { if (/not authorized|unauthorized/i.test(e.message)) { throw new Error(`Grant code write permission on the PR's project before merging: ${e.message}`) } else throw e }

Prevention

When it happens

Trigger: Calling POST /merge-pull-request as an authenticated user whose effective permissions on the project do not include code write (e.g. read-only role, guest access, or the PR belongs to a project the user cannot push to).

Common situations: Bot/API token scoped to a role without write access; user moved to a read-only group; PR lives in a different project than assumed and permission is checked against pullRequest.getProject().

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/d135e78585d90b2d. Report an issue: GitHub.