Why does constrain by X and Y fail when both extend SecurityGate?

← Web Services · Ref: Q1295

When 'constrain by X and Y' names two functions that both extend the same base (both SecurityGate or both CORSPolicy), the compiler emits E12064.

WHAT CAUSES E12064

Duplicate roles in a two-reference constraint:

  constrain by GateAlpha and GateBeta

If both GateAlpha and GateBeta extend SecurityGate, the roles are duplicated.

WHY ONE OF EACH

The runtime applies the two constraints differently:

  SecurityGate: called with HTTPContext, authenticates the request
  CORSPolicy: called with origin String, validates cross-origin access

Two gates or two policies create ambiguity — which one runs first? What happens if they disagree?

CORRECT PATTERN

One SecurityGate + one CORSPolicy:

  constrain by JwtGate and AllowedOrigins

The router knows exactly which function handles authentication and which handles CORS.

SINGLE CONSTRAINT IS FINE

If you only need authentication without CORS:

  constrain by JwtGate

Or only CORS without authentication (unusual):

  constrain by MyCors

See Q1292 for security posture overview. See Q1293 for constraint resolution. See Q1294 for constraint type validation.

Example

defines module qa.webdeep.duplicaterole

  defines constant

    jsonType <- "application/json"
    noCache <- "no-cache"
    langEn <- "en"
    okStatus <- 200

  defines function

    <?-
      SecurityGate for JWT token validation.
    -?>
    JwtGate is SecurityGate
      -> context as HTTPContext
      <- rtn as HTTPContext: context

    <?-
      CORSPolicy that allows known origins.
    -?>
    KnownOrigins is CORSPolicy
      -> origin as String
      <- rtn as Boolean: true

  defines service

    <?-
      Correct: one SecurityGate + one CORSPolicy.
      The router knows which function handles which concern.
    -?>
    ValidDualConstraint :/api/dual constrain by JwtGate and KnownOrigins

      resource() as GET for :/resource
        <- response as HTTPResponse: () with trait HTTPResponse
          override content()
            <- rtn as String: `{"dual": "gate+cors"}`
          override status() as pure
            <- rtn as Integer: okStatus
          override contentType() as pure
            <- rtn as String: jsonType
          override cacheControl() as pure
            <- rtn as String: noCache
          override contentLanguage() as pure
            <- rtn as String: langEn
          default operator ?

  defines application

    DuplicateRoleApp
      register ValidDualConstraint()

  defines program

    DuplicateConstraintRoleDemo()
      stdout <- Stdout()
      stdout.println("Duplicate constraint role rules:")
      stdout.println("  'constrain by Gate and Cors' -> valid (different roles)")
      stdout.println("  'constrain by Gate1 and Gate2' -> E12064 (both SecurityGate)")
      stdout.println("  'constrain by Cors1 and Cors2' -> E12064 (both CORSPolicy)")
Other ways to ask this
  • What is E12064 duplicate constraint role?
  • Can I use two SecurityGate functions in constrain by?
  • Why must the two constraint references have different roles?
  • How do I combine SecurityGate and CORSPolicy in one clause?

Coming from another language?

Java: Spring Security allows chaining multiple filters of the same type — order is explicit in filter chain. Python: multiple decorators stack. Go: middleware wraps in order. Rust: Actix Transform chain. EK9: at most one SecurityGate and one CORSPolicy per constraint clause, enforced at compile time. No ambiguous filter ordering.

Keywords: constrain, role, service, CORSPolicy, duplicate, SecurityGate, http, E12064