theonedev/onedev · error · ExplicitException

Directory (tenant) ID needs to be specified to generate refr

Error message

Directory (tenant) ID needs to be specified to generate refresh token

What it means

Office365Connector's refresh-token callback reads the tenantId input from the edit form. The Azure AD directory (tenant) ID is required to build the Microsoft OAuth authorize/token endpoints, so a null value raises an ExplicitException.

Source

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

	@Editable(order=10100, description="Specify timeout in seconds when communicating with mail server")
	@Min(value=5, message="This value should not be less than 5")
	public int getTimeout() {
		return timeout;
	}

	public void setTimeout(int timeout) {
		this.timeout = timeout;
	}

	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);

View on GitHub (pinned to d44925c47c)

Solutions

  1. Copy the Directory (tenant) ID from the Azure Portal app registration 'Overview' page into the form.
  2. If no app registration exists, create one in Azure AD with SMTP.Send / IMAP.AccessAsUser.All / offline_access permissions.
  3. Fill the field before clicking generate refresh token — it cannot be derived automatically.

Example fix

// before
tenantId = null;
// after
tenantId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
Defensive patterns

Strategy: validation

Validate before calling

if (!tenantId || tenantId.trim() === "") throw new Error("Fill Directory (tenant) ID before generating refresh token");

Try / catch

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

Prevention

When it happens

Trigger: Clicking the generate-refresh-token action in the Office365 mail connector form while the 'Directory (tenant) ID' input is empty.

Common situations: User hasn't created the Azure app registration yet; copied only client ID/secret from Azure portal; confused tenant ID with client ID fields.

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