instructure/canvas-lms · error · Errors::InvalidTypeCast

type_cast Proc must take exactly one argument for setting `#

Error message

type_cast Proc must take exactly one argument for setting `#{setting_name}`

What it means

Guard in Canvas::Operations::BaseConcerns::Settings#validate_type_cast!: a type_cast declared as a Proc for a canvas operation setting does not take exactly one argument, so Errors::InvalidTypeCast is raised at definition time. It's a developer-facing config validation, not a runtime data error.

Solutions

  1. Rewrite the Proc to take exactly one argument and bind other values via closure
  2. Move extra conversion parameters into the closure body, not the signature
  3. Use a simple Symbol cast if no custom logic is needed

Example fix

// before
setting(:port, default: 80, type_cast: ->(v, base) { v.to_i(base) })
// after
setting(:port, default: 80, type_cast: ->(v) { v.to_i })
Defensive patterns

Strategy: validation

Validate before calling

raise 'proc must take 1 arg' unless type_cast.is_a?(Proc) && type_cast.arity == 1

Try / catch

rescue CanvasOperations::Errors::InvalidTypeCast
  value = default
end

Prevention

When it happens

Trigger: setting(:x, default: 0, type_cast: ->(v, base=10) { v.to_i(base) }) or a zero-arg proc like type_cast: -> { nil }.

Common situations: Reusing multi-argument converters; lambda vs proc arity quirks when writing -> without parameters; wrapping methods that have optional extra params.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15). Data as JSON: /api/errors/93e2bfc02ef02f44. Report an issue: GitHub.

Appendix: source

Thrown at lib/canvas_operations/base_concerns/settings.rb:134

        #
        # Always returns the setting for the operation's current shard's cluster.
        define_method(setting_name) do
          self.class.send(setting_name, cluster:)
        end
        protected setting_name
      end

      def validate_type_cast!(type_cast, setting_name)
        case type_cast
        when Symbol
          # Setting values are always Strings, so ensure the type_cast method exists on String
          unless SETTINGS_TYPE_INSTANCE.respond_to?(type_cast)
            raise Errors::InvalidTypeCast,
                  "Unsupported type_cast `#{type_cast}` for setting `#{setting_name}`. #{SETTINGS_TYPE_INSTANCE.class} does not respond to `#{type_cast}`."
          end
        when Proc
          unless type_cast.arity == 1
            raise Errors::InvalidTypeCast, "type_cast Proc must take exactly one argument for setting `#{setting_name}`"
          end
        else
          raise Errors::InvalidTypeCast, "Unsupported type_cast `#{type_cast}` for setting `#{setting_name}`"
        end
      end

      def settings_key(setting_name, cluster:)
        "clusters/#{cluster}/#{operation_name}/#{setting_name}"
      end
    end
  end
end

View on GitHub (pinned to 1c9f0bb801)