{"id":"9bc5822db436c36c","repo":"pallets/flask","slug":"when-cert-is-an-sslcontext-object-key-is","errorCode":null,"errorMessage":"When \"--cert\" is an SSLContext object, \"--key\" is not used.","messagePattern":"When \"--cert\" is an SSLContext object, \"--key\" is not used\\.","errorType":"validation","errorClass":"click.BadParameter","httpStatus":null,"severity":"error","filePath":"src/flask/cli.py","lineNumber":849,"sourceCode":"    \"\"\"\n    cert = ctx.params.get(\"cert\")\n    is_adhoc = cert == \"adhoc\"\n\n    try:\n        import ssl\n    except ImportError:\n        is_context = False\n    else:\n        is_context = isinstance(cert, ssl.SSLContext)\n\n    if value is not None:\n        if is_adhoc:\n            raise click.BadParameter(\n                'When \"--cert\" is \"adhoc\", \"--key\" is not used.', ctx, param\n            )\n\n        if is_context:\n            raise click.BadParameter(\n                'When \"--cert\" is an SSLContext object, \"--key\" is not used.',\n                ctx,\n                param,\n            )\n\n        if not cert:\n            raise click.BadParameter('\"--cert\" must also be specified.', ctx, param)\n\n        ctx.params[\"cert\"] = cert, value\n\n    else:\n        if cert and not (is_adhoc or is_context):\n            raise click.BadParameter('Required when using \"--cert\".', ctx, param)\n\n    return value\n\n\nclass SeparatedPathType(click.Path):","sourceCodeStart":831,"sourceCodeEnd":867,"githubUrl":"https://github.com/pallets/flask/blob/6a2f545bfd8ed31e19066a299296917e034aca58/src/flask/cli.py#L831-L867","documentation":"Raised by `_validate_key` when `--cert` resolved to an imported `ssl.SSLContext` object and `--key` was also passed. Flask's `--cert` accepts a dotted import path to an SSLContext; such a context already carries its certificate chain and private key (loaded via `load_cert_chain`), so a separate `--key` is meaningless and rejected.","triggerScenarios":"`flask run --cert mymodule:ctx --key key.pem` where `mymodule.ctx` is an `ssl.SSLContext` instance; `_ssl_context` import resolution succeeds and `isinstance(cert, ssl.SSLContext)` is true, then the `--key` callback raises.","commonSituations":"Migrating from file-based cert/key flags to a programmatic SSLContext for custom TLS settings (ciphers, client auth) while leaving the old `--key` flag in a launch script or Procfile.","solutions":["Drop `--key` and load the key inside the context: call `ctx.load_cert_chain('cert.pem', 'key.pem')` in the module that defines the SSLContext.","Alternatively pass plain file paths instead of a context: `flask run --cert cert.pem --key key.pem`."],"exampleFix":"# before\nflask run --cert mymodule:ctx --key key.pem\n# after (mymodule.py)\nctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)\nctx.load_cert_chain(\"cert.pem\", \"key.pem\")\n# then: flask run --cert mymodule:ctx","handlingStrategy":"type-guard","validationCode":"import ssl\nif isinstance(cert, ssl.SSLContext) and key is not None:\n    raise SystemExit(\"SSLContext already contains the key; drop --key\")","typeGuard":"import ssl\n\ndef is_ssl_context(obj) -> bool:\n    return isinstance(obj, ssl.SSLContext)","tryCatchPattern":null,"preventionTips":["When you build an ssl.SSLContext, load the key via load_cert_chain and pass only the context","Never pass a separate key alongside a preconfigured SSLContext","Centralize TLS setup in one helper that returns either (cert, key) paths or a context, never both"],"tags":["flask","cli","tls","ssl-context","dev-server"],"analyzedSha":"6a2f545bfd8ed31e19066a299296917e034aca58","analyzedAt":"2026-07-31T19:13:49.921Z","schemaVersion":2}