theonedev/onedev · error · UnauthorizedException

No package write permission for project: ${project.getPath()

Error message

No package write permission for project: ${project.getPath()}

What it means

checkProject throws UnauthorizedException when a write operation (publish/upload) is requested and SecurityUtils.canWritePack(project) is false — the authenticated user lacks package write permission on the project.

Source

Thrown at server-plugin/server-plugin-pack-helm/src/main/java/io/onedev/server/plugin/pack/helm/HelmPackHandler.java:259

                packService.createOrUpdate(pack, List.of(packBlob), true);
                response.setStatus(SC_CREATED);
            }));
        } else {
            throw new ClientException(SC_METHOD_NOT_ALLOWED, "Method not allowed");
        }
    }

    @Override
    public String getApiKey(HttpServletRequest request) {
        return null;
    }

	private Project checkProject(Long projectId, boolean needsToWrite) {
		var project = projectService.load(projectId);
		if (!project.isPackManagement()) {
			throw new ClientException(SC_NOT_ACCEPTABLE, "Package management not enabled for project '" + project.getPath() + "'");
		} else if (needsToWrite && !SecurityUtils.canWritePack(project)) {
			throw new UnauthorizedException("No package write permission for project: " + project.getPath());
		} else if (!needsToWrite && !SecurityUtils.canReadPack(project)) {
			throw new UnauthorizedException("No package read permission for project: " + project.getPath());
		}
		return project;
	}

	private String getDownloadUrl(Pack pack) {
		return String.format("/%s/~helm/%s-%s.tgz",
				pack.getProject().getPath(), pack.getName(), pack.getVersion());
	}

	@Override
	public List<String> normalize(List<String> pathSegments) {
        pathSegments = new ArrayList<>(pathSegments);
        if (pathSegments.get(pathSegments.size() - 1).equals("charts")) {
            pathSegments.remove(pathSegments.size() - 1);
            if (pathSegments.get(0).equals("api")) 
                pathSegments.remove(0);

View on GitHub (pinned to d44925c47c)

Solutions

  1. Grant the user/job token package write permission (role with 'Write packages' on the project)
  2. Switch the CI job to an access token/account with pack write access
  3. Verify you are publishing to a project you are a member of with sufficient role
  4. Check Project -> Access Control and the job's token permissions

Example fix

// before: read-only token
curl -H "Authorization: Bearer <read-token>" -T chart.tgz ...
// after: use a token with pack write permission
curl -H "Authorization: Bearer <write-token>" -T chart.tgz ...
Defensive patterns

Strategy: validation

Validate before calling

// before publishing, verify access
var me = GET /api/auth/user
var acl = GET /api/projects/{path}/authorizations
if (!acl.canWritePack) throw new SecurityException("token lacks pack write permission");

Try / catch

try { publishChart(); } catch (UnauthorizedException e) { log.error("no pack write permission: {}", e.getMessage()); requestWriteAccess(); }

Prevention

When it happens

Trigger: POST/PUT of a chart to /~helm by a user who can read but not write packs; CI job tokens without write scope; anonymous or read-only accounts attempting to publish.

Common situations: Deploy pipelines using a read-only access token, users not added to a role with 'Write packages' permission, or publishing to a project where only maintainers may write packs.

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