EpicGames/lore · error · anyhow::Error

[environment.endpoint] auth_url and [server.auth]…

Error message

[environment.endpoint] auth_url and [server.auth] resource_claim are both set: with auth_url configured, every check calls the auth service and resource_claim does nothing. Remove auth_url to authorize from the token's resource claim, or remove resource_claim to stay on the gRPC auth service.

What it means

select_repository_authorizer rejects a config where both auth_url and [server.auth] resource_claim are set: with auth_url configured every authorization check calls the external auth service, so resource_claim would silently do nothing. This is treated as a mutually-exclusive configuration conflict and startup fails.

Solutions

  1. Remove auth_url from [environment.endpoint] to authorize from the token's resource_claim.
  2. Or remove resource_claim from [server.auth] to keep using the gRPC auth service.
  3. Re-run startup after the change; validate_auth_config should now select AllowAll/AuthClient/claim-based authorizer cleanly.

Example fix

// before (config)
[server.auth]
jwt_issuer = "https://auth.example.com"
jwt_audience = "aud"
resource_claim = "permissions"
[environment.endpoint]
auth_url = "https://auth.example.com"
// after (claim-based auth)
[server.auth]
jwt_issuer = "https://auth.example.com"
jwt_audience = "aud"
resource_claim = "permissions"
Defensive patterns

Strategy: validation

Validate before calling

// config-load validation
if config.environment.endpoint.auth_url.is_some()
    && config.server.auth.as_ref().and_then(|a| a.resource_claim.as_deref()).is_some() {
    return Err(anyhow!("auth_url and server.auth.resource_claim are mutually exclusive"));
}

Try / catch

match select_repository_authorizer(&auth_opt, &auth_url_opt) {
    Ok(sel) => start_server(sel),
    Err(e) => { eprintln!("conflicting auth config: {e:#}"); std::process::exit(2); }
}

Prevention

When it happens

Trigger: Configuring environment.endpoint.auth_url AND server.auth.resource_claim simultaneously; select_repository_authorizer matches (Some(_), Some(_)) and bails during repository_authorizer startup or validate_auth_config.

Common situations: Operators enabling local resource-claim authorization but forgetting to remove the previously set auth_url; merging config files where both auth modes accumulated; toggling between gRPC auth-service mode and claim-based mode during migration.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


AI-assisted analysis of EpicGames/lore@074eb0b0d1 (2026-09-13). Data as JSON: /api/errors/7b07947bc17b1f65. Report an issue: GitHub.

Appendix: source

Thrown at lore-server/src/authnz/repository_authorizer.rs:218

/// - `auth_url` set → the gRPC online auth check
/// - `resource_claim` set → `ResourceGrants`
/// - otherwise → `GlobalGrants`
pub fn select_repository_authorizer(
    auth: Option<&AuthSettings>,
    auth_url: Option<&str>,
) -> anyhow::Result<AuthorizerSelection> {
    let Some(auth) = auth else {
        return match auth_url {
            None => Ok(AuthorizerSelection::AllowAll),
            Some(_) => bail!(
                "[environment.endpoint] auth_url is set but [server.auth] is not: without \
                 [server.auth] tokens are not verified. Add [server.auth] (jwt_issuer, jwt_audience) \
                 to enable verification, or remove auth_url."
            ),
        };
    };
    match (auth_url, auth.resource_claim.as_deref()) {
        (Some(_), Some(_)) => bail!(
            "[environment.endpoint] auth_url and [server.auth] resource_claim are both set: \
             with auth_url configured, every check calls the auth service and resource_claim \
             does nothing. Remove auth_url to authorize from the token's resource claim, or \
             remove resource_claim to stay on the gRPC auth service."
        ),
        (Some(_), None) => Ok(AuthorizerSelection::AuthClient),
        (None, Some(_)) => Ok(AuthorizerSelection::ResourceGrants),
        (None, None) => Ok(AuthorizerSelection::GlobalGrants),
    }
}

/// Creates the authorizer [`select_repository_authorizer`] picks for this
/// configuration. Built once at startup and shared by every server.
pub fn repository_authorizer(
    auth: Option<&AuthSettings>,
    auth_url: Option<String>,
) -> anyhow::Result<Arc<dyn RepositoryAuthorizer>> {
    let selection = select_repository_authorizer(auth, auth_url.as_deref())?;

View on GitHub (pinned to 074eb0b0d1)