{"record":{"id":"606014c176de9ab1","repo":"apache/superset","slug":"invalid-certificate","errorCode":null,"errorMessage":"Invalid certificate","messagePattern":"Invalid certificate","errorType":"validation","errorClass":"ValidationError","httpStatus":422,"severity":"error","filePath":"superset/databases/schemas.py","lineNumber":238,"sourceCode":"            ]\n        ) from ex\n    if current_app.config.get(\"PREVENT_UNSAFE_DB_CONNECTIONS\", True):\n        try:\n            check_sqlalchemy_uri(uri)\n        except SupersetSecurityException as ex:\n            raise ValidationError([str(ex)]) from ex\n    return value\n\n\ndef server_cert_validator(value: str) -> str:\n    \"\"\"\n    Validate the server certificate\n    \"\"\"\n    if value:\n        try:\n            parse_ssl_cert(value)\n        except CertificateException as ex:\n            raise ValidationError([_(\"Invalid certificate\")]) from ex\n    return value\n\n\ndef encrypted_extra_validator(value: str | None) -> None:\n    \"\"\"\n    Validate that encrypted extra is a valid JSON string\n    \"\"\"\n    if value:\n        try:\n            json.loads(value)\n        except json.JSONDecodeError as ex:\n            raise ValidationError(\n                [_(\"Field cannot be decoded by JSON. %(msg)s\", msg=str(ex))]\n            ) from ex\n\n\ndef masked_encrypted_extra_validator(value: str) -> None:\n    \"\"\"","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/apache/superset/blob/f4587218dd19d046c3e4d00063e7d27f8a2ed354/superset/databases/schemas.py#L220-L256","documentation":"server_cert_validator runs on the server certificate field of database create/update: when a non-empty value is supplied, parse_ssl_cert attempts to load it as a PEM certificate and a CertificateException becomes ValidationError('Invalid certificate'). The stored cert is later used to verify the database TLS connection.","triggerScenarios":"POST/PUT /api/v1/database/ with server_cert containing anything that is not a parseable PEM certificate: a public key only, a CA bundle in DER (binary) form, a cert with mangled base64, or text pasted with missing BEGIN/END lines.","commonSituations":"Pasting the TLS server's public key instead of the certificate; copying from a terminal that dropped the header/footer; uploading DER instead of PEM; concatenation with stray blank characters inside base64 blocks.","solutions":["Provide the PEM-encoded certificate including the -----BEGIN CERTIFICATE----- / -----END CERTIFICATE----- lines.","Convert DER to PEM: openssl x509 -inform der -in cert.cer -out cert.pem.","Verify locally: openssl x509 -in cert.pem -noout (must succeed).","Leave the field empty if the connection does not require a pinned server cert."],"exampleFix":"# before\nserver_cert: \"MIIDdzCCAl+gAwIBAgIEAgAAuTANBg\"  # bare base64 blob\n\n# after\nserver_cert: \"-----BEGIN CERTIFICATE-----\\nMIIDdzCCAl+gAwIBAgIEAgAAuTANBg...\\n-----END CERTIFICATE-----\\n\"","handlingStrategy":"validation","validationCode":"import ssl\n\ndef is_pem_cert(pem: str) -> bool:\n    try:\n        ssl.PEM_cert_to_DER_cert(pem)\n        return True\n    except (ValueError, TypeError):\n        return False","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always include the full PEM including BEGIN/END CERTIFICATE lines.","Convert DER with openssl x509 -inform der before pasting.","Sanity-check with: openssl x509 -in cert.pem -noout."],"tags":["database","tls","certificate","validation"],"backgroundTag":null,"analyzedSha":"f4587218dd19d046c3e4d00063e7d27f8a2ed354","analyzedAt":"2026-08-14T22:39:27.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}