theonedev/onedev · error · UnauthorizedException
Unauthorized
Error message
Unauthorized
What it means
Thrown by ArtifactResource.uploadArtifact when the authenticated user lacks manage-build permission on the build's project. Publishing artifacts requires SecurityUtils.canManageBuild(build), a stronger permission than mere project access.
Source
Thrown at server-core/src/main/java/io/onedev/server/rest/resource/ArtifactResource.java:100
var projectId = build.getProject().getId();
var buildNumber = build.getNumber();
var normalizedPath = normalizeArtifactPath(artifactPath);
return os -> {
buildService.downloadArtifact(projectId, buildNumber, normalizedPath, os);
};
}
@Api(order=300, description = "Upload artifact to specified path")
@Path("/{buildId}/{artifactPath:(.*)}")
@POST
@Consumes(APPLICATION_OCTET_STREAM)
public Response uploadArtifact(
@PathParam("buildId") Long buildId,
@PathParam("artifactPath") @Api(example = "path/to/file") String artifactPath,
InputStream input) {
Build build = buildService.load(buildId);
if (!SecurityUtils.canManageBuild(build))
throw new UnauthorizedException();
buildService.uploadArtifact(build.getProject().getId(), build.getNumber(),
normalizeArtifactPath(artifactPath), input);
return ok().build();
}
@Api(order=400, description = "Delete artifact of specified path, or delete all artifacts " +
"if artifact path is not specified")
@Path("/{buildId}{artifactPath:(/.*)?}")
@DELETE
public Response deleteArtifact(
@PathParam("buildId") Long buildId,
@PathParam("artifactPath") @Api(example = "/path/to/directoryOrFile") String artifactPath) {
Build build = buildService.load(buildId);
if (!SecurityUtils.canManageBuild(build))
throw new UnauthorizedException();
buildService.deleteArtifact(build, normalizeArtifactPath(artifactPath));View on GitHub (pinned to d44925c47c)
Solutions
- Use credentials with Build Management permission on the project
- Assign the job's token/user a role that allows managing builds (e.g. project maintainer)
- If running inside a OneDev job, use the built-in build credential rather than a custom one
Example fix
// before curl -u reader:token -X POST --data-binary @app.jar .../builds/42/artifacts/target/app.jar // after curl -u maintainer:token -X POST --data-binary @app.jar .../builds/42/artifacts/target/app.jar
Defensive patterns
Strategy: validation
Validate before calling
if (!canManageBuild(tokenUser, buildId)) throw new Error('manage-build permission required to upload artifacts'); Type guard
function canManage(u, b) { return u?.managedProjectIds?.includes(b?.projectId); } Try / catch
try { uploadArtifact(buildId, path, stream); } catch (e) { if (/Unauthorized/i.test(e.message)) { throw new Error('Credential lacks Build Management permission'); } throw e; } Prevention
- Give CI service accounts at least maintainer role on their project
- Prefer OneDev's built-in job token for artifact publishing
- Verify permission scope of personal access tokens
When it happens
Trigger: POST (upload) to /builds/{buildId}/artifacts/{artifactPath} by a user who can view but not manage the build; build-agent or job token with insufficient project role.
Common situations: Uploading artifacts from an external script with a read-only user; project role downgraded from maintainer to read; using personal access token of a non-member.
Understand the failure class
Background: "You do not have permission" / 403 Forbidden errors: authenticated but not allowed — causes and fixes across open-source libraries — this error's family across 31 libraries.
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06).
Data as JSON: /api/errors/393658676620d37b.
Report an issue: GitHub.