instructure/canvas-lms · error · ArgumentError
Proc attribute # returned nil when # is required.
Error message
Proc attribute #{name} returned nil when #{name} is required. What it means
EventStream's attr_config allows attributes whose value is a Proc resolved lazily on read. If such an attribute was declared `required` and its Proc (or callable) returns nil when read, attr_config raises ArgumentError rather than emitting events with a nil required field.
Solutions
- Fix the Proc to return a non-nil value (add fallback/default inside the proc)
- Remove `required: true` from the attribute if nil is actually acceptable
- Guard the event emission site so the proc's input always exists
- Log/inspect which attribute is named in the message and audit its data source
Example fix
// before
attr_config :account_id, required: true, type: String
... proc { account&.id }
// after
... proc { account&.id || Canvas::EventStream::NULL_ACCOUNT_ID } Defensive patterns
Strategy: try-catch
Type guard
def callable_non_nil?(v) v.respond_to?(:call) && !v.call.nil? end
Try / catch
begin
emit_event(stream)
rescue ArgumentError => e
raise unless e.message.include?('returned nil when')
Rails.logger.error("EventStream proc returned nil: #{e.message}")
end Prevention
- Add `|| default` fallbacks inside required attribute procs
- Only mark attributes required when their data always exists
- Test event emission from background jobs where session data is nil
When it happens
Trigger: Defining an EventStream::Stream/Index with an attribute configured via a Proc, marking it required, and the Proc returning nil at read time (e.g. the Proc reads session/context data that is absent, or reads a model field that is nil).
Common situations: Livestream attribute procs relying on `current_user`, `request`, or a DB record that is nil in background jobs or after object destruction; misordered initialization so the proc reads before its subject is set.
Related errors
- block is required if module_name is not passed
- Cannot include a concatenation in a merge.
- cannot pass both a module_name and a block
- Missing required asset parameter #
- missing required attributes: #
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/1ac03f7cb5a1eafe.
Report an issue: GitHub.
Appendix: source
Thrown at gems/event_stream/lib/event_stream/attr_config.rb:62
type = options[:type]
typecast = CASTS[type]
end
required = !options.key?(:default)
unless required
default = options[:default]
default = typecast.call(name, default) if default && typecast
attr_config_defaults[name] = default
end
define_method(name) do |*args|
raise ArgumentError if args.length > 1
if args.empty?
value = attr_config_values[name]
if type != Proc && value.respond_to?(:call)
value = value.call
if required && value.nil?
raise ArgumentError, "Proc attribute #{name} returned nil when #{name} is required."
end
return typecast.call(name, value) if typecast
return value
end
return value
end
value = args.first
if typecast && !value.respond_to?(:call)
value = typecast.call(name, value)
end
attr_config_values[name] = value
end
end
end
View on GitHub (pinned to 1c9f0bb801)