theonedev/onedev · error · UnauthorizedException

No package write permission for project:

Error message

No package write permission for project: 

What it means

Thrown by checkProject when a write operation (npm publish or unpublish) is attempted by a user who lacks pack write permission on the project. It raises UnauthorizedException, which OneDev surfaces as HTTP 401 to the npm client.

Source

Thrown at server-plugin/server-plugin-pack-npm/src/main/java/io/onedev/server/plugin/pack/npm/NpmPackHandler.java:583

			}
		}
	}

	@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;
	}
	
	@Override
	public List<String> normalize(List<String> pathSegments) {
		return pathSegments;
	}

}

View on GitHub (pinned to d44925c47c)

Solutions

  1. Set a valid access token with package write permission in .npmrc: //onedev.example.com/:_authToken=<token>.
  2. Grant the user/job's role Pack Write (or higher) on the project in OneDev's authorization settings.
  3. Verify the Bearer token actually maps to an account with write access (test with a metadata GET first).
  4. Regenerate an expired token from User Profile -> Access Tokens and update .npmrc.

Example fix

// before (.npmrc)
//onedev.example.com/:_authToken=<readonly-token>
// after
//onedev.example.com/:_authToken=<token-of-user-with-pack-write>
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check write access before publishing
const resp = await fetch(`${registryUrl}/${pkgName}`, { headers: { Authorization: `Bearer ${token}` } });
if (!resp.ok) throw new Error(`Registry auth failed: ${resp.status} — check token and Pack Write permission`);

Try / catch

try {
  await npmPublish();
} catch (e) {
  if (String(e).includes('No package write permission') || e.code === 'E401') {
    console.error('Publish unauthorized: use a token whose user has Pack Write on the project');
  } else throw e;
}

Prevention

When it happens

Trigger: PUT publish or DELETE unpublish where SecurityUtils.canWritePack(project) is false for the authenticated user — typically the account used in .npmrc is a job token or read-only user.

Common situations: Using a CI job secret token that only has read access; missing or expired access token in .npmrc (_authToken); user not added to the project with sufficient role; anonymous access configured instead of a credential.

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