instructure/canvas-lms · error · ConfigError
kafka_events connection requires both sasl_username and…
Error message
kafka_events connection requires both sasl_username and sasl_password when SASL is in use
What it means
Canvas::KafkaEvents::Config#validate! ensures that if SASL authentication is configured (sasl_configured?), both sasl_username and sasl_password are present (sasl_credentials_complete?). A partial SASL config would produce a Kafka client that cannot authenticate, so ConfigError is raised at connection setup.
Solutions
- Set both sasl_username and sasl_password in the kafka_events DynamicSettings/config for the environment
- If SASL is not intended, remove the SASL mechanism/security-protocol keys so sasl_configured? is false
- Verify secret rotation kept both keys together
- Restart/re-validate config after fixing so validate! passes
Example fix
# before config: sasl_mechanism: PLAIN sasl_username: canvas // after config: sasl_mechanism: PLAIN sasl_username: canvas sasl_password: <secret>
Defensive patterns
Strategy: validation
Validate before calling
raise 'SASL incomplete' if sasl_configured && (sasl_username.blank? || sasl_password.blank?)
Type guard
complete = cfg.is_a?(Hash) && cfg[:sasl_username].present? && cfg[:sasl_password].present?
Try / catch
begin config.validate! rescue Canvas::KafkaEvents::ConfigError => e Rails.logger.error(e.message) raise end
Prevention
- Store both SASL secrets together as one secret bundle
- Validate kafka_events config at deploy/boot time
- Diff DynamicSettings trees between environments before rollout
When it happens
Trigger: Building/validating kafka_events config where SASL mechanism/security protocol is set but only one of sasl_username or sasl_password is provided in DynamicSettings or config files.
Common situations: Secrets manager missing one of the two SASL keys, config partially rotated, copy-paste of Kafka settings omitting the password, consul hierarchy overriding one key to empty.
Related errors
- kafka_events has brokers configured but required topic(s)…
- A partner ID is required to use Academic Benchmarks
- A partner key is required to use Academic Benchmarks
- an object with an interface for loading settings must be…
- an object with an interface for loading settings must be…
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/005e072f420a26f8.
Report an issue: GitHub.
Appendix: source
Thrown at lib/canvas/kafka_events/config.rb:78
"sasl.mechanisms": sasl_mechanism,
"sasl.username": sasl_username,
"sasl.password": sasl_password,
"client.id": client_id,
acks: "all",
"enable.idempotence": "true",
"compression.type": "zstd",
"socket.keepalive.enable": "true",
"linger.ms": "50",
"message.timeout.ms": message_timeout_ms.to_s,
"queue.buffering.max.messages": queue_buffering_max_messages.to_s,
"reconnect.backoff.ms": reconnect_backoff_ms.to_s,
"reconnect.backoff.max.ms": reconnect_backoff_max_ms.to_s,
}.compact
end
def validate!
if sasl_configured? && !sasl_credentials_complete?
raise ConfigError,
"kafka_events connection requires both sasl_username and sasl_password when SASL is in use"
end
missing = Events.topic_keys.reject { |key| topic_for(key).present? }
return if missing.empty?
raise ConfigError,
"kafka_events has brokers configured but required topic(s) missing from DynamicSettings: #{missing.join(", ")}"
end
private
def load_operational_config
parsed = YAML.safe_load(DynamicSettings.find(tree: :private)["kafka_events.yml", failsafe: nil] || "{}")
parsed.is_a?(Hash) ? parsed : {}
rescue => e
Rails.logger.warn("Kafka operational settings load error: #{e.message}")
{}View on GitHub (pinned to 1c9f0bb801)