{"record":{"id":"e83d43c856763b42","repo":"sebastianbergmann/phpunit","slug":"method-s-may-not-return-value-of-type-s-its-dec","errorCode":null,"errorMessage":"Method %s may not return value of type %s, its declared return type is \"%s\"","messagePattern":"Method (.+?) may not return value of type (.+?), its declared return type is \"(.+?)\"","errorType":"exception","errorClass":"IncompatibleReturnValueException","httpStatus":null,"severity":"error","filePath":"src/Framework/MockObject/Runtime/AbstractInvocationImplementation.php","lineNumber":299,"sourceCode":"        return $_valueMap;\n    }\n\n    /**\n     * @param array<mixed> $values\n     *\n     * @throws IncompatibleReturnValueException\n     */\n    private function ensureTypeOfReturnValues(array $values): void\n    {\n        $configuredMethod = $this->configuredMethod();\n\n        if ($configuredMethod === null) {\n            return;\n        }\n\n        foreach ($values as $value) {\n            if (!$configuredMethod->mayReturn($value)) {\n                throw new IncompatibleReturnValueException(\n                    $configuredMethod,\n                    $value,\n                );\n            }\n        }\n    }\n}\n","sourceCodeStart":281,"sourceCodeEnd":307,"githubUrl":"https://github.com/sebastianbergmann/phpunit/blob/f123cdb2a2d49f15025794166cfed8bda8627dd2/src/Framework/MockObject/Runtime/AbstractInvocationImplementation.php#L281-L307","documentation":"Thrown by ensureTypeOfReturnValues() when a value passed to willReturn() is not accepted by the doubled method's declared return type (ConfigurableMethod::mayReturn()). PHPUnit only checks this when it knows the method's return type (configuredMethod !== null); values that pass PHP's own type checks are required, so this is a static type-compatibility guard before the stub is ever called.","triggerScenarios":"->method('getCount')->willReturn('5') on a method declared : int; ->willReturn(null) on a non-nullable return type; ->willReturn(new Foo) where the method returns Bar; willReturnConsecutiveCalls() entries where one element violates the type.","commonSituations":"Tests written before a return type was added to production code (tightening types in refactors breaks them); stubbing with string literals for int/float methods under strict comparisons; returning null from a stub for a method made non-nullable; copying expectations between similar classes with different return types.","solutions":["Return a value of the declared type: cast, construct the right class, or use a matching literal.","For nullable return types, willReturn(null) is fine; otherwise pick a real value.","When the value is computed, use ->willReturnCallback(fn () => ...) and let PHP's type system verify the callback's return.","If the production signature changed, update the stub to the new return type instead of suppressing the check."],"exampleFix":"// before\n/** @return int */\npublic function count(): int;\n$stub->method('count')->willReturn('42');\n\n// after\n$stub->method('count')->willReturn(42);","handlingStrategy":"type-guard","validationCode":"$rm = new ReflectionMethod(C::class, 'getCount');\n$value = 42;\n$ok = $value === null && $rm->getReturnType()->allowsNull();\n// or simply assert before stubbing:\nassert($value instanceof ($rm->getReturnType()->getName()) || !is_object($value));","typeGuard":"function valueMatchesReturnType(ReflectionMethod $m, mixed $value): bool\n{\n    $type = $m->getReturnType();\n    if ($type === null) {\n        return true;\n    }\n    if ($value === null) {\n        return $type->allowsNull();\n    }\n\n    return match ($type->getName()) {\n        'int' => is_int($value),\n        'string' => is_string($value),\n        'bool' => is_bool($value),\n        'float' => is_float($value) || is_int($value),\n        default => $value instanceof $type->getName(),\n    };\n}","tryCatchPattern":"try {\n    $mock->method('getCount')->willReturn($value);\n} catch (PHPUnit\\Framework\\MockObject\\IncompatibleReturnValueException $e) {\n    // coerce or rebuild the value to satisfy the declared return type\n}","preventionTips":["Mirror the production signature exactly when stubbing; update stubs whenever return types are tightened.","Enable PHPStan/Psalm on the tests directory — willReturn() type errors are caught statically in IDEs with the phpunit plugin.","For computed values prefer willReturnCallback() and let the return type of the callback enforce correctness."],"tags":["phpunit","mock-object","return-type","type-mismatch","willreturn"],"backgroundTag":"return-type-mismatch","analyzedSha":"f123cdb2a2d49f15025794166cfed8bda8627dd2","analyzedAt":"2026-08-23T01:20:58.058Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}