theonedev/onedev · error · UnauthorizedException

No package read permission for project: ${project.path}

Error message

No package read permission for project: ${project.path}

What it means

checkProject throws UnauthorizedException when the request is read-only (needsToWrite=false, e.g. downloading or listing gems) but SecurityUtils.canReadPack(project) is false. The user is not allowed to read packages of the project, so the gem fetch is refused before any blob lookup.

Source

Thrown at server-plugin/server-plugin-pack-gem/src/main/java/io/onedev/server/plugin/pack/gem/GemPackHandler.java:497

	}

	@Override
	public String getApiKey(HttpServletRequest request) {
		var authzHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
		if (authzHeader != null&& authzHeader.toLowerCase().startsWith("bearer "))
			return StringUtils.substringAfter(authzHeader, " ");
		else
			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 UserMarshal getGemVersion(String version) {
		return new UserMarshal("Gem::Version", newArrayList(version));
	}
	
	private UserMarshal getGemRequirement(Map<String, UserMarshal> requiredVersions) {
		var requirements = new ArrayList<>();
		for (var entry: requiredVersions.entrySet()) 
			requirements.add(newArrayList(entry.getKey(), entry.getValue()));
		var value = new ArrayList<>();
		value.add(requirements);
		return new UserMarshal("Gem::Requirement", value);	
	}
	
	private UserMarshal getGemVersion(MappingNode node) {

View on GitHub (pinned to d44925c47c)

Solutions

  1. Grant the user/group 'Read Package' (or Write) permission in Project -> Permissions.
  2. Configure credentials in the gem client for the OneDev gem host (e.g. via :gem_sources entry in ~/.gem/credentials or token in URL).
  3. If packages should be public, enable anonymous pack read via project/global permissions.
  4. Check for expired tokens and re-authenticate.

Example fix

# ~/.gem/credentials
:onedev: MYTOKEN
# then
gem sources -a https://onedev.example.com/~project/gem --config-file ~/.gem/credentials
Defensive patterns

Strategy: validation

Validate before calling

// confirm credentials are configured for the OneDev gem host before install/fetch
// ~/.gem/credentials must contain the token for :onedev host
// test: curl -u user:token https://onedev/~project/gem/api/v1/versions

Try / catch

try {
    gemFetch(source, spec);
} catch (UnauthorizedException e) {
    if (String(e).contains('read permission')) throw new SecurityException("Add Pack Read permission or configure gem credentials", e);
    throw e;
}

Prevention

When it happens

Trigger: gem install/fetch/spec request handled by GemPackHandler where the authenticated (or anonymous) user lacks Pack Read permission on the project.

Common situations: Private project packages fetched without credentials; gem client on another machine missing the stored token; anonymous access to a project whose packages are restricted; expired/rotated access token still configured in gem sources.

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