{"record":{"id":"05eeefdc8e7c7c81","repo":"phalcon/cphalcon","slug":"argument-at-position-must-have-a-type","errorCode":null,"errorMessage":"Argument at position {} must have a type","messagePattern":"Argument at position (.+?) must have a type","errorType":"exception","errorClass":"ArgumentTypeRequired","httpStatus":null,"severity":"error","filePath":"phalcon/Di/Service/Builder.zep","lineNumber":209,"sourceCode":"        }\n\n        return instance;\n    }\n\n    /**\n     * Resolves a constructor/call parameter\n     *\n     * @return mixed\n     */\n    private function buildParameter(<DiInterface> container, int position,  array argument)\n    {\n        var type, name, value, instanceArguments;\n\n        /**\n         * All the arguments must have a type\n         */\n        if unlikely !fetch type, argument[\"type\"] {\n            throw new ArgumentTypeRequired(position);\n        }\n\n        switch type {\n            /**\n             * If the argument type is 'service', we obtain the service from the\n             * DI\n             */\n            case \"service\":\n                if unlikely !fetch name, argument[\"name\"] {\n                    throw new MissingParameterKey(\"name\", position);\n                }\n\n                return container->get(name);\n\n            /**\n             * If the argument type is 'parameter', we assign the value as it is\n             */\n            case \"parameter\":","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/phalcon/cphalcon/blob/b7419de9cd0a8a3f48441ead84c9f8415d463e25/phalcon/Di/Service/Builder.zep#L191-L227","documentation":"Thrown by Phalcon\\Di\\Service\\Builder::buildParameter() when a constructor/call argument defined in the array-based DI definition has no 'type' key. Every entry under 'arguments' must be an array describing HOW to resolve the value: ['type' => 'service'|'parameter'|'instance', ...]. Without the type the builder cannot decide whether to fetch a service, use a literal, or instantiate a class.","triggerScenarios":"Calling $di->set('foo', ['className' => 'Foo', 'arguments' => [['value' => 'bar']]]) and then resolving the service via $di->get('foo'), $di['foo'], or injecting it into another service. The throw happens at resolve time, not at set() time, because the array definition is parsed lazily.","commonSituations":"Writing array DI definitions by hand and assuming arguments are plain values (the old string/positional style), migrating from a different container (Symfony/Pimple pass raw values), or copy-pasting a definition and deleting the type line. Also hit when 'arguments' is built dynamically and one element is a scalar/empty array.","solutions":["Add a 'type' key to the failing argument: 'parameter' for literals, 'service' to resolve another DI service by name, 'instance' to construct a class (Phalcon 5 name; 'class' in Phalcon 3).","Use the error position (0-based) to find the exact broken element in your 'arguments' array.","If the value is a plain literal, switch the whole definition to a closure: $di->set('foo', function() { return new Foo('bar'); }) which skips array parsing entirely.","Validate definitions at boot (see defense) so a mis-typed definition fails during a startup smoke test instead of at first resolve."],"exampleFix":"// before\n$di->set(\n    'invoiceMailer',\n    [\n        'className' => \\App\\InvoiceMailer::class,\n        'arguments' => [\n            ['value' => 'notifications@example.com'],   // no type -> ArgumentTypeRequired\n        ],\n    ]\n);\n\n// after\n$di->set(\n    'invoiceMailer',\n    [\n        'className' => \\App\\InvoiceMailer::class,\n        'arguments' => [\n            ['type' => 'parameter', 'value' => 'notifications@example.com'],\n        ],\n    ]\n);","handlingStrategy":"validation","validationCode":"const DI_ARGUMENT_KEYS = ['service' => 'name', 'parameter' => 'value', 'instance' => 'className'];\n\nfunction assertValidDiDefinition(array $definition, string $serviceId): void\n{\n    $args = $definition['arguments'] ?? [];\n    foreach ($args as $position => $arg) {\n        if (!is_array($arg) || !isset($arg['type'])) {\n            throw new InvalidArgumentException(sprintf(\n                'DI service \"%s\": argument %d has no \"type\"', $serviceId, $position\n            ));\n        }\n    }\n}\n\n// at boot, after registering array definitions:\nassertValidDiDefinition($di->getDefinition('foo') /* or your source array */, 'foo');","typeGuard":"function isDiArgumentDefinition(mixed $arg): bool\n{\n    if (!is_array($arg) || !isset($arg['type']) || !is_string($arg['type'])) {\n        return false;\n    }\n    $required = ['service' => 'name', 'parameter' => 'value', 'instance' => 'className'];\n\n    return array_key_exists($arg['type'], $required)\n        && isset($arg[$required[$arg['type']]);\n}","tryCatchPattern":"try {\n    $service = $di->get('foo');\n} catch (\\Phalcon\\Di\\Exceptions\\ArgumentTypeRequired $e) {\n    // definition bug: log with the service name and fail loudly\n    $logger->error('DI definition missing argument type: ' . $e->getMessage());\n    throw $e;\n}","preventionTips":["Validate array definitions at boot with a small schema check (type + required companion key) so failures surface during deploy smoke tests.","Prefer closure definitions for anything non-trivial - arrays are only worth it for config-driven wiring.","Keep definitions in one place (config files) and lint them in CI with the same validator used at boot."],"tags":["phalcon","dependency-injection","di","configuration","service-container"],"backgroundTag":"di-definition-invalid","analyzedSha":"b7419de9cd0a8a3f48441ead84c9f8415d463e25","analyzedAt":"2026-08-21T06:21:18.811Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}