Skip to content

System type invokes — custom handler runs alongside built-in default rather than replacing it? #289

@corinagum

Description

@corinagum

Question

When registering a custom signin/failure handler via @app.on_signin_failure(), both the custom handler and the built-in default handler execute. In TypeScript and C#, registering a custom handler for the same route replaces the default one.

Is this intentional behavior for the Python SDK? I noticed the Python SDK uses additive middleware-style routing where all matching handlers chain together, so this may be by design. But it means there's no way to suppress the default behavior for these types of invokes.

Note that this only applies to type: system invokes (e.g. signin/verifyState, signin/tokenExchange, signin/failure) where the SDK registers built-in default handlers, so the practical impact is narrow.

Behavior comparison

In TypeScript, when a new route is added with the same name, the router removes the existing route before adding the new one — so a custom signin.failure handler replaces the default.

In Python, on_signin_failure adds the handler without removing the existing default, so both execute.

Reproduction

@app.on_signin_failure()
async def handle_signin_failure(ctx):
    failure = ctx.activity.value
    print(f"Custom handler: {failure.code} - {failure.message}")
    await ctx.send("Sign-in failed. Please contact your admin.")

When signin/failure is received, both the built-in default handler (which logs a warning) and the custom handler above fire.

Context

  • Confirmed via live testing in Teams with a resourcematchfailed failure
  • Currently documenting this as a Python-specific note in the user authentication guide

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions