theonedev/onedev · error · ExplicitException

User principal name needs to be specified to generate refres

Error message

User principal name needs to be specified to generate refresh token

What it means

Office365Connector's refresh-token callback finally validates the userPrincipalName input — the mailbox's UPN (usually the email address). Without it, the refresh token cannot be scoped to the sending mailbox, so an ExplicitException is thrown.

Source

Thrown at server-plugin/server-plugin-mail-office365/src/main/java/io/onedev/server/plugin/mail/office365/Office365Connector.java:172

	private static String getTokenEndpoint(String tenantId) {
		return String.format("https://login.microsoftonline.com/%s/oauth2/v2.0/token", tenantId);
	}

	@SuppressWarnings("unused")
	private static RefreshToken.Callback getRefreshTokenCallback() {
		String tenantId = (String) EditContext.get().getInputValue("tenantId");
		if (tenantId == null)
			throw new ExplicitException("Directory (tenant) ID needs to be specified to generate refresh token");
		String clientId = (String) EditContext.get().getInputValue("clientId");
		if (clientId == null)
			throw new ExplicitException("Application (client) ID needs to be specified to generate refresh token");
		String clientSecret = (String) EditContext.get().getInputValue("clientSecret");
		if (clientSecret == null)
			throw new ExplicitException("Client secret needs to be specified to generate refresh token");

		String userPrincipalName = (String) EditContext.get().getInputValue("userPrincipalName");
		if (userPrincipalName == null)
			throw new ExplicitException("User principal name needs to be specified to generate refresh token");

		Collection<String> scopes = Lists.newArrayList(
				"https://outlook.office.com/SMTP.Send",
				"https://outlook.office.com/IMAP.AccessAsUser.All",
				"offline_access");

		String authorizeEndpoint = String.format(
				"https://login.microsoftonline.com/%s/oauth2/v2.0/authorize", tenantId);
		String tokenEndpoint = getTokenEndpoint(tenantId);

		return new RefreshToken.Callback() {

			@Override
			public String getAuthorizeEndpoint() {
				return authorizeEndpoint;
			}

			@Override

View on GitHub (pinned to d44925c47c)

Solutions

  1. Enter the user principal name (full email address of the mailbox that will send mail) in the form.
  2. Ensure the UPN belongs to a licensed mailbox in the same tenant as the app registration.
  3. Complete every required field, then re-run generate refresh token.

Example fix

// before
userPrincipalName = null;
// after
userPrincipalName = "build-notifications@contoso.com";
Defensive patterns

Strategy: validation

Validate before calling

if (!userPrincipalName || userPrincipalName.trim() === "") throw new Error("Fill User principal name before generating refresh token");

Try / catch

try {
    generateRefreshToken();
} catch (ExplicitException e) {
    alert("Complete the connector form first: " + e.getMessage());
}

Prevention

When it happens

Trigger: Generating a refresh token with tenantId, clientId, and clientSecret filled but 'User principal name' empty in the Office365 connector form.

Common situations: User forgets the mailbox field after entering app credentials; confusion between display name and UPN; shared mailbox used but UPN omitted.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06). Data as JSON: /api/errors/2378be55372ac68d. Report an issue: GitHub.