{"record":{"id":"fdc3a58f0cafd8de","repo":"puppetlabs/puppet","slug":"callable-tuple-may-not-have-a-size-constraint-when","errorCode":null,"errorMessage":"Callable tuple may not have a size constraint when used as args","messagePattern":"Callable tuple may not have a size constraint when used as args","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/puppet/pops/types/types.rb","lineNumber":2181,"sourceCode":"  end\n\n  # If set, describes min and max required of the given types - if max > size of\n  # types, the last type entry repeats\n  #\n  attr_reader :size_type\n\n  attr_reader :types\n\n  def accept(visitor, guard)\n    super\n    @size_type.accept(visitor, guard) unless @size_type.nil?\n    @types.each { |elem| elem.accept(visitor, guard) }\n  end\n\n  # @api private\n  def callable_args?(callable_t, guard)\n    unless size_type.nil?\n      raise ArgumentError, 'Callable tuple may not have a size constraint when used as args'\n    end\n\n    params_tuple = callable_t.param_types\n    param_block_t = callable_t.block_type\n    arg_types = @types\n    arg_block_t = arg_types.last\n    if arg_block_t.kind_of_callable?(true, guard)\n      # Can't pass a block to a callable that doesn't accept one\n      return false if param_block_t.nil?\n\n      # Check that the block is of the right tyṕe\n      return false unless param_block_t.assignable?(arg_block_t, guard)\n\n      # Check other arguments\n      arg_count = arg_types.size - 1\n      params_size_t = params_tuple.size_type || PIntegerType.new(*params_tuple.size_range)\n      return false unless params_size_t.assignable?(PIntegerType.new(arg_count, arg_count), guard)\n","sourceCodeStart":2163,"sourceCodeEnd":2199,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/pops/types/types.rb#L2163-L2199","documentation":"PTupleType#callable_args? answers whether this tuple can be spread as the argument list of a Callable type. A tuple carrying a size_type (Tuple[String, Integer, 1, 3]) denotes a variable number of elements, which cannot be matched element-wise against a signature, so the method raises ArgumentError instead of guessing. It is a private API of the pops type checker; users normally hit it only indirectly, when a Callable is combined with sized tuple/array types in aliases or in Ruby-side signature checks.","triggerScenarios":"Calling tuple.callable_args?(callable, guard) in Ruby on a tuple built with a size type, e.g. PTupleType.new(types, PIntegerType.new(1, 3)); type aliases that put a sized Tuple or an Array type on the argument side of a Callable, then trigger an assignability/callability check during compilation.","commonSituations":"Advanced callback/dispatch type aliases (Callable[Array[String, 1]]); Ruby tools embedding pops (custom functions, linters) doing signature checks; Puppet upgrades that change when the checker invokes callable_args?.","solutions":["Remove the size constraint from the tuple used on the argument side: Tuple[String, Integer] instead of Tuple[String, Integer, 1, 3].","Declare the callable's parameters explicitly (Callable[String, Integer, 2]) instead of one sized tuple type.","In Ruby, rebuild the tuple without its size type before checking: PTupleType.new(tuple.types).","If it reproduces from plain Puppet DSL with no Ruby API use, minimize the case and report it upstream as a type-system bug."],"exampleFix":"# before (type alias)\ntype MyCallback = Callable[Tuple[String, 1, 2]]   # sized tuple as args -> ArgumentError when checked\n\n# after\ntype MyCallback = Callable[String, String]        # declare the parameters explicitly","handlingStrategy":"validation","validationCode":"# Ruby: reject sized tuples before the call\nif tuple.respond_to?(:size_type) && !tuple.size_type.nil?\n  raise ArgumentError, 'tuple has a size constraint; strip it before callable_args?'\nend\ntuple.callable_args?(callable, guard)","typeGuard":"def fixed_size_tuple?(t)\n  t.is_a?(Puppet::Pops::Types::PTupleType) && t.size_type.nil?\nend","tryCatchPattern":"begin\n  tuple.callable_args?(callable, guard)\nrescue ArgumentError => e\n  raise unless e.message =~ /size constraint/\n  PTupleType.new(tuple.types).callable_args?(callable, guard)  # retry without the size type\nend","preventionTips":["Never attach a size range to a tuple that will be used in argument position.","Prefer explicit parameter lists in Callable types over tuple/array parameter specs.","Treat this ArgumentError as an invariant violation: fix the type definition rather than rescuing in production code."],"tags":["puppet","type-system","callable","tuple","size-constraint"],"backgroundTag":"callable-signature-mismatch","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}