langgenius/dify · error · BadRequest

invalid grant_type

Error message

invalid grant_type

What it means

Flask BadRequest (HTTP 400) raised at oauth_server.py:204 in OAuthServerUserTokenApi.post (POST /console/api/oauth/provider/token) when OAuthGrantType(payload.grant_type) raises ValueError — the supplied grant_type string is not one of the enum members (e.g. not 'authorization_code' or 'refresh_token'). This is the first validation in the token endpoint.

Source

Thrown at api/controllers/console/auth/oauth_server.py:204

        return jsonable_encoder(
            {
                "code": code,
            }
        )


@console_ns.route("/oauth/provider/token")
class OAuthServerUserTokenApi(Resource):
    @setup_required
    @console_ns.expect(console_ns.models[OAuthTokenRequest.__name__])
    @console_ns.response(200, "Success", console_ns.models[OAuthProviderTokenResponse.__name__])
    @oauth_server_client_id_required
    @model_validate(OAuthTokenRequest)
    def post(self, payload: OAuthTokenRequest, oauth_provider_app: OAuthProviderApp):
        try:
            grant_type = OAuthGrantType(payload.grant_type)
        except ValueError:
            raise BadRequest("invalid grant_type")
        match grant_type:
            case OAuthGrantType.AUTHORIZATION_CODE:
                if not payload.code:
                    raise BadRequest("code is required")

                if payload.client_secret != oauth_provider_app.client_secret:
                    raise BadRequest("client_secret is invalid")

                if payload.redirect_uri not in oauth_provider_app.redirect_uris:
                    raise BadRequest("redirect_uri is invalid")

                access_token, refresh_token = OAuthServerService.sign_oauth_access_token(
                    grant_type, code=payload.code, client_id=oauth_provider_app.client_id
                )
                return jsonable_encoder(
                    {
                        "access_token": access_token,
                        "token_type": "Bearer",

View on GitHub (pinned to ef8544b173)

Solutions

  1. Use only the grant_type values the server supports: 'authorization_code' to exchange a code, or 'refresh_token' to rotate tokens.
  2. Check the OAuthGrantType enum definition for the canonical string values and match them exactly (case-sensitive).
  3. Ensure the field is present in the JSON body — an empty/None value will also fail enum construction.
  4. Update the client if a version change altered the accepted grant_type strings.
Defensive patterns

Strategy: validation

Validate before calling

const ALLOWED = new Set(['authorization_code', 'refresh_token']);
if (!ALLOWED.has(grantType)) {
  throw new Error(`Unsupported grant_type '${grantType}'`);
}

Type guard

function isSupportedGrantType(v: string): v is 'authorization_code' | 'refresh_token' {
  return v === 'authorization_code' || v === 'refresh_token';
}

Try / catch

try {
  await requestToken({grant_type: grantType, ...});
} catch (e) {
  if (/invalid grant_type/i.test(e.message)) { correctGrantType(); } else throw e;
}

Prevention

When it happens

Trigger: POST /oauth/provider/token with a grant_type the server does not recognize (typo, unsupported value like 'password' or 'client_credentials', or missing). The enum constructor raises ValueError -> caught -> BadRequest.

Common situations: OAuth client built for a different grant flow than this server supports; schema drift after an upgrade that renamed grant types; or a malformed test payload.

Related errors


AI-assisted analysis of langgenius/dify@ef8544b173 (2026-08-12). Data as JSON: /api/errors/3b4864833ec0f0dc. Report an issue: GitHub.