{"record":{"id":"b1ae0f75dc5e314d","repo":"puppetlabs/puppet","slug":"tries-must-be-an-integer-1","errorCode":null,"errorMessage":"Tries must be an integer >= 1","messagePattern":"Tries must be an integer >= 1","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/puppet/type/exec.rb","lineNumber":360,"sourceCode":"\n      defaultto 300\n    end\n\n    newparam(:tries) do\n      desc \"The number of times execution of the command should be tried.\n        This many attempts will be made to execute the command until an\n        acceptable return code is returned. Note that the timeout parameter\n        applies to each try rather than to the complete set of tries.\"\n\n      munge do |value|\n        if value.is_a?(String)\n          unless value =~ /^\\d+$/\n            raise ArgumentError, _(\"Tries must be an integer\")\n          end\n\n          value = Integer(value)\n        end\n        raise ArgumentError, _(\"Tries must be an integer >= 1\") if value < 1\n\n        value\n      end\n\n      defaultto 1\n    end\n\n    newparam(:try_sleep) do\n      desc \"The time to sleep in seconds between 'tries'.\"\n\n      munge do |value|\n        if value.is_a?(String)\n          unless value =~ /^[-\\d.]+$/\n            raise ArgumentError, _(\"try_sleep must be a number\")\n          end\n\n          value = Float(value)\n        end","sourceCodeStart":342,"sourceCodeEnd":378,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/type/exec.rb#L342-L378","documentation":"After munging, the exec type enforces `raise ... if value < 1`, so any syntactically valid integer of zero or below raises ArgumentError 'Tries must be an integer >= 1'. At least one execution attempt must happen, so 0 or negative retry counts are meaningless.","triggerScenarios":"`tries => 0`, `tries => -2`, or strings '0'/'00' (digit-only, so they pass the regex, then fail the >= 1 check); computed values from Hiera or arithmetic that evaluate to 0 on some nodes.","commonSituations":"Using 0 to mean 'disable retrying' (it actually requests zero attempts); computing tries as a difference without a floor; environment-specific Hiera overrides setting 0 in dev tiers.","solutions":["Use 1 or higher; 1 is the default and means a single attempt.","If the intent is 'no retries', omit `tries` entirely instead of using 0.","Clamp computed values: `tries => max(1, $computed)`.","Fail early in the manifest: `assert_type(Integer[1, default], $tries)`."],"exampleFix":"// before\nexec { 'retry_thing':\n  command => '/opt/app/job.sh',\n  tries   => 0,\n}\n\n// after: omit tries (default 1) or set >= 1\nexec { 'retry_thing':\n  command => '/opt/app/job.sh',\n  tries   => 3,\n}","handlingStrategy":"validation","validationCode":"// Puppet\nunless $tries =~ Integer and $tries >= 1 {\n  fail(\"exec: tries must be >= 1, got '${tries}'\")\n}","typeGuard":"def positive_tries?(v)\n  n = v.is_a?(Integer) ? v : (v.to_i if v.is_a?(String) && v.match?(/\\A\\d+\\z/))\n  !n.nil? && n >= 1\nend","tryCatchPattern":null,"preventionTips":["Omit tries when you want a single attempt (default 1).","Clamp computed values: max(1, $n).","Use assert_type(Integer[1, default], $tries) to fail at compile time.","Remember tries counts total attempts, not retries."],"tags":["puppet","exec","tries","range-validation"],"backgroundTag":"invalid-parameter-value","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}