{"record":{"id":"272a7c0d9500237d","repo":"sebastianbergmann/phpunit","slug":"parameter-count-for-invocation-s-is-too-low","errorCode":null,"errorMessage":"Parameter count for invocation %s is too low.","messagePattern":"Parameter count for invocation (.+?) is too low\\.","errorType":"exception","errorClass":"ExpectationFailedException","httpStatus":null,"severity":"error","filePath":"src/Framework/MockObject/Runtime/Rule/Parameters.php","lineNumber":123,"sourceCode":"\n        $invocation           = $this->invocation;\n        $invocationParameters = $invocation->parameters();\n\n        if (count($invocationParameters) < count($this->parameters)) {\n            $message = 'Parameter count for invocation %s is too low.';\n\n            // The user called `->with($this->anything())`, but may have meant\n            // `->withAnyParameters()`.\n            //\n            // @see https://github.com/sebastianbergmann/phpunit-mock-objects/issues/199\n            if (count($this->parameters) === 1 &&\n                $this->parameters[0]::class === IsAnything::class) {\n                $message .= \"\\nTo allow 0 or more parameters with any value, omit ->with() or use ->withAnyParameters() instead.\";\n            }\n\n            $this->incrementAssertionCount();\n\n            throw new ExpectationFailedException(\n                sprintf($message, $invocation->toString()),\n            );\n        }\n\n        $parameters = $this->parameters($invocation);\n\n        foreach ($this->parameters as $i => $parameter) {\n            $other = null;\n\n            if ($parameter instanceof Callback && $parameter->isVariadic()) {\n                $other = $invocationParameters;\n            } elseif (isset($invocationParameters[$i])) {\n                $other = $invocationParameters[$i];\n            }\n\n            $this->incrementAssertionCount();\n\n            $parameter->evaluate(","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/sebastianbergmann/phpunit/blob/f123cdb2a2d49f15025794166cfed8bda8627dd2/src/Framework/MockObject/Runtime/Rule/Parameters.php#L105-L141","documentation":"PHPUnit throws this when an actual call to the mocked method passed fewer arguments than the number of constraints you gave to ->with(). Parameters::doVerify() compares the invocation's argument list against the configured constraints; if the real call supplies fewer values (typically because trailing parameters are optional and were omitted), verification fails. PHPUnit even appends a hint when the single constraint was anything(): it suspects you wrote ->with($this->anything()) to mean 'any parameters', which actually means 'exactly one parameter of any value'.","triggerScenarios":"->with($this->anything(), $this->anything()) on a method whose optional second argument the SUT omits; ->with($this->anything()) on a zero-argument call — the message then suggests omitting ->with() or using ->withAnyParameters(); default-valued parameters not passed explicitly by the code under test.","commonSituations":"Calling $mock->log() with no args while the test expects with('msg'); variadic or optional parameters added/removed in a signature refactor; PHPUnit 9-to-10 migration where with($this->anything()) no longer tolerates a different arity; test doubles for methods with many defaults where production code passes only the first argument.","solutions":["If any number of arguments is acceptable, replace ->with(...) with ->withAnyParameters() (the failure message itself suggests this for the single-anything() case).","Otherwise make the constraints match the real arity: one constraint per argument the code actually passes, using $this->anything() only for arguments you do not care about but that ARE passed.","Check the doubled method's signature for optional/variadic parameters and mirror that shape in with().","If the code under test should pass the argument, fix that call site rather than loosening the expectation.","For variadic matching pass a variadic Callback constraint so one constraint covers the remaining arguments."],"exampleFix":"// before\n$logger->expects($this->once())->method('log')->with($this->anything());\n$logger->log(); // called with zero arguments\n\n// after: explicitly allow zero or more arguments of any value\n$logger->expects($this->once())->method('log')->withAnyParameters();","handlingStrategy":"validation","validationCode":"// Before writing with(), check the doubled method's signature and count the\n// arguments the SUT actually passes (optional args may be omitted):\n$ref = new ReflectionMethod($sut::class, 'log');\n$required = $ref->getNumberOfRequiredParameters();\n// If the call may pass zero args, do not use with() at all:\n// ->withAnyParameters() accepts 0 or more.","typeGuard":"// Narrow before configuring: does the method accept the arity you are about to constrain?\nfunction acceptsArity(object|string $classOrInstance, string $method, int $arity): bool\n{\n    $r = new ReflectionMethod($classOrInstance, $method);\n\n    return $arity <= $r->getNumberOfParameters()\n        && $arity >= $r->getNumberOfRequiredParameters();\n}","tryCatchPattern":null,"preventionTips":["Use ->withAnyParameters() when argument count can vary; ->with($this->anything()) means exactly one argument.","Mirror the real call's arity in with(): one constraint per actually-passed argument, anything() only for passed-but-ignored values.","Re-check expectations after changing signatures with optional or variadic parameters.","Use a variadic Callback constraint to absorb trailing arguments in one constraint."],"tags":["phpunit","mock","argument-count","with-constraints"],"backgroundTag":"mock-argument-count-mismatch","analyzedSha":"f123cdb2a2d49f15025794166cfed8bda8627dd2","analyzedAt":"2026-08-23T01:20:58.058Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}