[Bug]: Nullable dependencies might trigger 500 return value
Nobody has claimed this yet.
- Dominant language
- PHP
- Stars
- 36.9k
- Forks
- 5.2k
- Avg merge
- 2d 3h
- Merged PRs (30d)
- 713
Description
⚠️ This issue respects the following points: ⚠️
- This is a bug, not a question or a configuration/webserver/proxy issue.
- This issue is not already reported on Github OR Nextcloud Community Forum (I've searched it).
- Nextcloud Server is up to date. See Maintenance and Release Schedule for supported versions.
- I agree to follow Nextcloud's Code of Conduct.
Bug description
Since some time it is possible to define dependency injector requirements with nullable types. The documentation states this is intended if the dependency can’t be found or build.
The building of a nullable dependency might fail and trigger PHP interpreter failure. As a result, the page is not rendered anymore but an error 500 is returned as final word of death. Further details see below.
Steps to reproduce
To simplify, I created a MWE app to show the problem.
- Clone the MWE into the apps folder of a dev environment. Name it
test_nullable_dias mentioned in the README. - Enable the app
- The app installs 4 navigation endpoints. Use the one ending in
/transitive. It is just http://nextcloud.local/index.php/apps/test_nullable_di/transitive in the case of Julius' dev environment. This will show a dummy test message without error. - The corresponding public page is
/transient-pub. Open it in a private browser tab. This will error out with a internal server error.
Expected behavior
Both pages (logged in and not logged in) should show the same dummy info message without an error message shown.
Especially the controller of the public page should show a valid page and internally use null values to represent non-resolvable dependencies resolved by the DI algorithm.
Development environment setup
Nextcloud Server version
master
Operating system
Other
PHP engine version
PHP 8.1
Web server
Apache (supported)
Database engine version
MariaDB
Is this bug present after an update or on a fresh install?
None
Are you using the Nextcloud Server Encryption module?
Encryption is Disabled
What user-backends are you using?
- Default user-backend (database)
- LDAP/ Active Directory
- SSO - SAML
- Other
Configuration report
{
"system": {
"debug": true,
"profiler": true,
"apps_paths": [
{
"path": "\/var\/www\/html\/apps",
"url": "\/apps",
"writable": false
},
{
"path": "\/var\/www\/html\/apps-extra",
"url": "\/apps-extra",
"writable": false
},
{
"path": "\/var\/www\/html\/apps-shared",
"url": "\/apps-shared",
"writable": false
},
{
"path": "\/var\/www\/html\/apps-writable",
"url": "\/apps-writable",
"writable": true
}
],
"allow_local_remote_servers": true,
"mail_from_address": "***REMOVED SENSITIVE VALUE***",
"mail_smtpmode": "smtp",
"mail_sendmailmode": "smtp",
"mail_domain": "***REMOVED SENSITIVE VALUE***",
"mail_smtphost": "***REMOVED SENSITIVE VALUE***",
"mail_smtpport": "1025",
"skeletondirectory": "\/skeleton",
"loglevel": 0,
"log_query": false,
"query_log_file": "\/var\/www\/html\/data\/query.log",
"diagnostics.logging": false,
"diagnostics.logging.threshold": 0,
"log.condition": {
"apps": [
"diagnostics",
"admin_audit"
]
},
"passwordsalt": "***REMOVED SENSITIVE VALUE***",
"secret": "***REMOVED SENSITIVE VALUE***",
"trusted_domains": [
"localhost",
"nextcloud",
"nextcloud.local",
"192.168.21.6",
"localhost",
"dev.nc.wolf-stuttgart.net"
],
"datadirectory": "***REMOVED SENSITIVE VALUE***",
"dbtype": "mysql",
"version": "32.0.0.0",
"overwrite.cli.url": "http:\/\/nextcloud.local,dev.nc.wolf-stuttgart.net",
"dbname": "***REMOVED SENSITIVE VALUE***",
"dbhost": "***REMOVED SENSITIVE VALUE***",
"dbport": "",
"dbtableprefix": "oc_",
"mysql.utf8mb4": true,
"dbuser": "***REMOVED SENSITIVE VALUE***",
"dbpassword": "***REMOVED SENSITIVE VALUE***",
"updater.release.channel": "git",
"installed": true,
"instanceid": "***REMOVED SENSITIVE VALUE***",
"lookup_server": "",
"redis": {
"host": "***REMOVED SENSITIVE VALUE***",
"port": 6379
},
"memcache.local": "\\OC\\Memcache\\Redis",
"memcache.locking": "\\OC\\Memcache\\Redis",
"trusted_proxies": "***REMOVED SENSITIVE VALUE***",
"maintenance": false,
"app_install_overwrite": [
"calendar",
"contacts",
"deck",
"spreed",
"circles",
"forms",
"collectives",
"appointments",
"polls",
"timetracker",
"epubviewer"
],
"theme": ""
}
}
List of activated Apps
Enabled:
- calendar: 5.2.0-rc.1
- cloud_federation_api: 1.15.0
- comments: 1.22.0
- contactsinteraction: 1.13.0
- cookbook: 0.11.3
- dashboard: 7.12.0
- dav: 1.34.0
- epubviewer: 1.7.1
- federatedfilesharing: 1.22.0
- federation: 1.22.0
- files: 2.4.0
- files_pdfviewer: 5.0.0-dev.0
- files_reminders: 1.5.0
- files_sharing: 1.24.0
- files_trashbin: 1.22.0
- files_versions: 1.25.0
- logreader: 5.0.0-dev.0
- lookup_server_connector: 1.20.0
- oauth2: 1.20.0
- profile: 1.1.0
- provisioning_api: 1.22.0
- recommendations: 5.0.0-dev.0
- settings: 1.15.0
- sharebymail: 1.22.0
- sociallogin: 5.9.2
- spreed: 21.0.0
- systemtags: 1.22.0
- test_nullable_di: 1.0.0
- theming: 2.7.0
- twofactor_backupcodes: 1.21.0
- updatenotification: 1.22.0
- user_status: 1.12.0
- viewer: 5.0.0-dev.0
- weather_status: 1.12.0
- webhook_listeners: 1.3.0
- workflowengine: 2.14.0
Disabled:
- admin_audit: 1.22.0
- encryption: 2.20.0
- files_external: 1.24.0
- hmr_enabler: 1.0.0 (installed 1.0.0)
- profiler: 1.4.0 (installed 1.4.0)
- snowflakestheme: 1.1.2 (installed 1.1.2)
- testing: 1.22.0
- timetracker: 0.0.83 (installed 0.0.83)
- user_ldap: 1.23.0
Nextcloud Signing status
Integrity checker has been disabled. Integrity cannot be verified.
Nextcloud Logs
{
"reqId": "zuWPyZD0K5oEhWMmtuRp",
"level": 3,
"time": "2025-03-18T18:23:03+00:00",
"remoteAddr": "192.168.21.4",
"user": false,
"app": "index",
"method": "GET",
"url": "/index.php/apps/test_nullable_di/transitive-pub",
"message": "OCA\\TestNullableDi\\Service\\InvalidService::__construct(): Argument #1 ($userId) must be of type string, null given",
"userAgent": "Mozilla/5.0 (X11; Linux x86_64; rv:135.0) Gecko/20100101 Firefox/135.0",
"version": "32.0.0.0",
"exception": {
"Exception": "TypeError",
"Message": "OCA\\TestNullableDi\\Service\\InvalidService::__construct(): Argument #1 ($userId) must be of type string, null given",
"Code": 0,
"Trace": [
{
"function": "__construct",
"class": "OCA\\TestNullableDi\\Service\\InvalidService",
"type": "->",
"args": [
null
]
},
{
"file": "/var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php",
"line": 98,
"function": "newInstanceArgs",
"class": "ReflectionClass",
"type": "->",
"args": [
[
null
]
]
},
{
"file": "/var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php",
"line": 106,
"function": "buildClass",
"class": "OC\\AppFramework\\Utility\\SimpleContainer",
"type": "->",
"args": [
{
"__class__": "ReflectionClass",
"name": "OCA\\TestNullableDi\\Service\\InvalidService"
}
]
},
{
"file": "/var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php",
"line": 124,
"function": "resolve",
"class": "OC\\AppFramework\\Utility\\SimpleContainer",
"type": "->",
"args": [
"OCA\\TestNullableDi\\Service\\InvalidService"
]
},
{
"file": "/var/www/html/lib/private/AppFramework/DependencyInjection/DIContainer.php",
"line": 440,
"function": "query",
"class": "OC\\AppFramework\\Utility\\SimpleContainer",
"type": "->",
"args": [
"OCA\\TestNullableDi\\Service\\InvalidService"
]
},
{
"file": "/var/www/html/lib/private/AppFramework/DependencyInjection/DIContainer.php",
"line": 412,
"function": "queryNoFallback",
"class": "OC\\AppFramework\\DependencyInjection\\DIContainer",
"type": "->",
"args": [
"OCA\\TestNullableDi\\Service\\InvalidService"
]
},
{
"file": "/var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php",
"line": 74,
"function": "query",
"class": "OC\\AppFramework\\DependencyInjection\\DIContainer",
"type": "->",
"args": [
"OCA\\TestNullableDi\\Service\\InvalidService",
true
]
},
{
"function": "OC\\AppFramework\\Utility\\{closure}",
"class": "OC\\AppFramework\\Utility\\SimpleContainer",
"type": "->",
"args": [
"*** sensitive parameters replaced ***"
]
},
{
"file": "/var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php",
"line": 98,
"function": "array_map",
"args": [
{
"__class__": "Closure"
},
[
"*** sensitive parameters replaced ***"
]
]
},
{
"file": "/var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php",
"line": 106,
"function": "buildClass",
"class": "OC\\AppFramework\\Utility\\SimpleContainer",
"type": "->",
"args": [
{
"__class__": "ReflectionClass",
"name": "OCA\\TestNullableDi\\Service\\TransitiveService"
}
]
},
{
"file": "/var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php",
"line": 124,
"function": "resolve",
"class": "OC\\AppFramework\\Utility\\SimpleContainer",
"type": "->",
"args": [
"OCA\\TestNullableDi\\Service\\TransitiveService"
]
},
{
"file": "/var/www/html/lib/private/AppFramework/DependencyInjection/DIContainer.php",
"line": 440,
"function": "query",
"class": "OC\\AppFramework\\Utility\\SimpleContainer",
"type": "->",
"args": [
"OCA\\TestNullableDi\\Service\\TransitiveService"
]
},
{
"file": "/var/www/html/lib/private/AppFramework/DependencyInjection/DIContainer.php",
"line": 412,
"function": "queryNoFallback",
"class": "OC\\AppFramework\\DependencyInjection\\DIContainer",
"type": "->",
"args": [
"OCA\\TestNullableDi\\Service\\TransitiveService"
]
},
{
"file": "/var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php",
"line": 74,
"function": "query",
"class": "OC\\AppFramework\\DependencyInjection\\DIContainer",
"type": "->",
"args": [
"OCA\\TestNullableDi\\Service\\TransitiveService",
true
]
},
{
"function": "OC\\AppFramework\\Utility\\{closure}",
"class": "OC\\AppFramework\\Utility\\SimpleContainer",
"type": "->",
"args": [
"*** sensitive parameters replaced ***"
]
},
{
"file": "/var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php",
"line": 98,
"function": "array_map",
"args": [
{
"__class__": "Closure"
},
[
{
"__class__": "ReflectionParameter",
"name": "userId"
},
"*** sensitive parameters replaced ***"
]
]
},
{
"file": "/var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php",
"line": 106,
"function": "buildClass",
"class": "OC\\AppFramework\\Utility\\SimpleContainer",
"type": "->",
"args": [
{
"__class__": "ReflectionClass",
"name": "OCA\\TestNullableDi\\Controller\\TransitivePageController"
}
]
},
{
"file": "/var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php",
"line": 124,
"function": "resolve",
"class": "OC\\AppFramework\\Utility\\SimpleContainer",
"type": "->",
"args": [
"OCA\\TestNullableDi\\Controller\\TransitivePageController"
]
},
{
"file": "/var/www/html/lib/private/AppFramework/DependencyInjection/DIContainer.php",
"line": 440,
"function": "query",
"class": "OC\\AppFramework\\Utility\\SimpleContainer",
"type": "->",
"args": [
"OCA\\TestNullableDi\\Controller\\TransitivePageController"
]
},
{
"file": "/var/www/html/lib/private/AppFramework/DependencyInjection/DIContainer.php",
"line": 412,
"function": "queryNoFallback",
"class": "OC\\AppFramework\\DependencyInjection\\DIContainer",
"type": "->",
"args": [
"OCA\\TestNullableDi\\Controller\\TransitivePageController"
]
},
{
"file": "/var/www/html/lib/private/AppFramework/App.php",
"line": 140,
"function": "query",
"class": "OC\\AppFramework\\DependencyInjection\\DIContainer",
"type": "->",
"args": [
"OCA\\TestNullableDi\\Controller\\TransitivePageController"
]
},
{
"file": "/var/www/html/lib/private/Route/Router.php",
"line": 307,
"function": "main",
"class": "OC\\AppFramework\\App",
"type": "::",
"args": [
"OCA\\TestNullableDi\\Controller\\TransitivePageController",
"indexPub",
{
"__class__": "OC\\AppFramework\\DependencyInjection\\DIContainer"
},
{
"_route": "test_nullable_di.transitivepage.indexpub"
}
]
},
{
"file": "/var/www/html/lib/base.php",
"line": 1043,
"function": "match",
"class": "OC\\Route\\Router",
"type": "->",
"args": [
"/apps/test_nullable_di/transitive-pub"
]
},
{
"file": "/var/www/html/index.php",
"line": 24,
"function": "handleRequest",
"class": "OC",
"type": "::",
"args": []
}
],
"File": "/var/www/html/apps-extra/test_nullable_di/lib/Service/InvalidService.php",
"Line": 9,
"message": "OCA\\TestNullableDi\\Service\\InvalidService::__construct(): Argument #1 ($userId) must be of type string, null given",
"exception": {
"xdebug_message": "<tr><th align='left' bgcolor='#f57900' colspan=\"5\"><span style='background-color: #cc0000; color: #fce94f; font-size: x-large;'>( ! )</span> TypeError: OCA\\TestNullableDi\\Service\\InvalidService::__construct(): Argument #1 ($userId) must be of type string, null given in /var/www/html/apps-extra/test_nullable_di/lib/Service/InvalidService.php on line <i>9</i></th></tr>\n<tr><th align='left' bgcolor='#e9b96e' colspan='5'>Call Stack</th></tr>\n<tr><th align='center' bgcolor='#eeeeec'>#</th><th align='left' bgcolor='#eeeeec'>Time</th><th align='left' bgcolor='#eeeeec'>Memory</th><th align='left' bgcolor='#eeeeec'>Function</th><th align='left' bgcolor='#eeeeec'>Location</th></tr>\n<tr><td bgcolor='#eeeeec' align='center'>1</td><td bgcolor='#eeeeec' align='center'>0.0001</td><td bgcolor='#eeeeec' align='right'>360752</td><td bgcolor='#eeeeec'>{main}( )</td><td title='/var/www/html/index.php' bgcolor='#eeeeec'>.../index.php<b>:</b>0</td></tr>\n<tr><td bgcolor='#eeeeec' align='center'>2</td><td bgcolor='#eeeeec' align='center'>0.0732</td><td bgcolor='#eeeeec' align='right'>3121152</td><td bgcolor='#eeeeec'>OC::handleRequest( )</td><td title='/var/www/html/index.php' bgcolor='#eeeeec'>.../index.php<b>:</b>24</td></tr>\n<tr><td bgcolor='#eeeeec' align='center'>3</td><td bgcolor='#eeeeec' align='center'>0.1148</td><td bgcolor='#eeeeec' align='right'>3414208</td><td bgcolor='#eeeeec'>OC\\Route\\Router->match( <span>$url = </span><span>'/apps/test_nullable_di/transitive-pub'</span> )</td><td title='/var/www/html/lib/base.php' bgcolor='#eeeeec'>.../base.php<b>:</b>1043</td></tr>\n<tr><td bgcolor='#eeeeec' align='center'>4</td><td bgcolor='#eeeeec' align='center'>0.1241</td><td bgcolor='#eeeeec' align='right'>3709856</td><td bgcolor='#eeeeec'>OC\\AppFramework\\App::main( <span>$controllerName = </span><span>'TransitivePageController'</span>, <span>$methodName = </span><span>'indexPub'</span>, <span>$container = </span><span>class OC\\AppFramework\\DependencyInjection\\DIContainer { private ${OC\\AppFramework\\Utility\\SimpleContainer}container = class Pimple\\Container { private $values = [...]; private $factories = class SplObjectStorage { ... }; private $protected = class SplObjectStorage { ... }; private $frozen = [...]; private $raw = [...]; private $keys = [...] }; private string $appName = 'test_nullable_di'; private $middleWares = []; private $server = class OC\\Server { private ${OC\\AppFramework\\Utility\\SimpleContainer}container = class Pimple\\Container { ... }; protected $appContainers = [...]; protected $hasNoAppContainer = [...]; protected $namespaces = [...]; private $webRoot = '' } }</span>, <span>$urlParams = </span><span>['_route' => 'test_nullable_di.transitivepage.indexpub']</span> )</td><td title='/var/www/html/lib/private/Route/Router.php' bgcolor='#eeeeec'>.../Router.php<b>:</b>307</td></tr>\n<tr><td bgcolor='#eeeeec' align='center'>5</td><td bgcolor='#eeeeec' align='center'>0.1250</td><td bgcolor='#eeeeec' align='right'>3722728</td><td bgcolor='#eeeeec'>OC\\AppFramework\\DependencyInjection\\DIContainer->query( <span>$name = </span><span>'OCA\\\\TestNullableDi\\\\Controller\\\\TransitivePageController'</span>, <span>$autoload = </span>??? )</td><td title='/var/www/html/lib/private/AppFramework/App.php' bgcolor='#eeeeec'>.../App.php<b>:</b>140</td></tr>\n<tr><td bgcolor='#eeeeec' align='center'>6</td><td bgcolor='#eeeeec' align='center'>0.1250</td><td bgcolor='#eeeeec' align='right'>3722728</td><td bgcolor='#eeeeec'>OC\\AppFramework\\DependencyInjection\\DIContainer->queryNoFallback( <span>$name = </span><span>'OCA\\\\TestNullableDi\\\\Controller\\\\TransitivePageController'</span> )</td><td title='/var/www/html/lib/private/AppFramework/DependencyInjection/DIContainer.php' bgcolor='#eeeeec'>.../DIContainer.php<b>:</b>412</td></tr>\n<tr><td bgcolor='#eeeeec' align='center'>7</td><td bgcolor='#eeeeec' align='center'>0.1250</td><td bgcolor='#eeeeec' align='right'>3722728</td><td bgcolor='#eeeeec'>OC\\AppFramework\\Utility\\SimpleContainer->query( <span>$name = </span><span>'OCA\\\\TestNullableDi\\\\Controller\\\\TransitivePageController'</span>, <span>$autoload = </span>??? )</td><td title='/var/www/html/lib/private/AppFramework/DependencyInjection/DIContainer.php' bgcolor='#eeeeec'>.../DIContainer.php<b>:</b>440</td></tr>\n<tr><td bgcolor='#eeeeec' align='center'>8</td><td bgcolor='#eeeeec' align='center'>0.1250</td><td bgcolor='#eeeeec' align='right'>3722728</td><td bgcolor='#eeeeec'>OC\\AppFramework\\Utility\\SimpleContainer->resolve( <span>$name = </span><span>'OCA\\\\TestNullableDi\\\\Controller\\\\TransitivePageController'</span> )</td><td title='/var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php' bgcolor='#eeeeec'>.../SimpleContainer.php<b>:</b>124</td></tr>\n<tr><td bgcolor='#eeeeec' align='center'>9</td><td bgcolor='#eeeeec' align='center'>0.1250</td><td bgcolor='#eeeeec' align='right'>3722936</td><td bgcolor='#eeeeec'>OC\\AppFramework\\Utility\\SimpleContainer->buildClass( <span>$class = </span><span>class ReflectionClass { public string $name = 'OCA\\\\TestNullableDi\\\\Controller\\\\TransitivePageController' }</span> )</td><td title='/var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php' bgcolor='#eeeeec'>.../SimpleContainer.php<b>:</b>106</td></tr>\n<tr><td bgcolor='#eeeeec' align='center'>10</td><td bgcolor='#eeeeec' align='center'>0.1250</td><td bgcolor='#eeeeec' align='right'>3724432</td><td bgcolor='#eeeeec'><a href='http://www.php.net/function.array-map' target='_new'>array_map</a>( <span>$callback = </span><span>class Closure { virtual $closure = "$this->OC\\AppFramework\\Utility\\{closure}" }</span>, <span>$array = </span><span>[0 => class ReflectionParameter { public string $name = 'userId' }, 1 => class ReflectionParameter { public string $name = 'transitiveService' }]</span> )</td><td title='/var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php' bgcolor='#eeeeec'>.../SimpleContainer.php<b>:</b>98</td></tr>\n<tr><td bgcolor='#eeeeec' align='center'>11</td><td bgcolor='#eeeeec' align='center'>0.1252</td><td bgcolor='#eeeeec' align='right'>3728136</td><td bgcolor='#eeeeec'>OC\\AppFramework\\Utility\\SimpleContainer->OC\\AppFramework\\Utility\\{closure:/var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php:61-98}( <span>$parameter = </span><span>class ReflectionParameter { public string $name = 'transitiveService' }</span> )</td><td title='/var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php' bgcolor='#eeeeec'>.../SimpleContainer.php<b>:</b>98</td></tr>\n<tr><td bgcolor='#eeeeec' align='center'>12</td><td bgcolor='#eeeeec' align='center'>0.1253</td><td bgcolor='#eeeeec' align='right'>3728240</td><td bgcolor='#eeeeec'>OC\\AppFramework\\DependencyInjection\\DIContainer->query( <span>$name = </span><span>'OCA\\\\TestNullableDi\\\\Service\\\\TransitiveService'</span>, <span>$autoload = </span><span>TRUE</span> )</td><td title='/var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php' bgcolor='#eeeeec'>.../SimpleContainer.php<b>:</b>74</td></tr>\n<tr><td bgcolor='#eeeeec' align='center'>13</td><td bgcolor='#eeeeec' align='center'>0.1253</td><td bgcolor='#eeeeec' align='right'>3728240</td><td bgcolor='#eeeeec'>OC\\AppFramework\\DependencyInjection\\DIContainer->queryNoFallback( <span>$name = </span><span>'OCA\\\\TestNullableDi\\\\Service\\\\TransitiveService'</span> )</td><td title='/var/www/html/lib/private/AppFramework/DependencyInjection/DIContainer.php' bgcolor='#eeeeec'>.../DIContainer.php<b>:</b>412</td></tr>\n<tr><td bgcolor='#eeeeec' align='center'>14</td><td bgcolor='#eeeeec' align='center'>0.1253</td><td bgcolor='#eeeeec' align='right'>3728240</td><td bgcolor='#eeeeec'>OC\\AppFramework\\Utility\\SimpleContainer->query( <span>$name = </span><span>'OCA\\\\TestNullableDi\\\\Service\\\\TransitiveService'</span>, <span>$autoload = </span>??? )</td><td title='/var/www/html/lib/private/AppFramework/DependencyInjection/DIContainer.php' bgcolor='#eeeeec'>.../DIContainer.php<b>:</b>440</td></tr>\n<tr><td bgcolor='#eeeeec' align='center'>15</td><td bgcolor='#eeeeec' align='center'>0.1253</td><td bgcolor='#eeeeec' align='right'>3728240</td><td bgcolor='#eeeeec'>OC\\AppFramework\\Utility\\SimpleContainer->resolve( <span>$name = </span><span>'OCA\\\\TestNullableDi\\\\Service\\\\TransitiveService'</span> )</td><td title='/var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php' bgcolor='#eeeeec'>.../SimpleContainer.php<b>:</b>124</td></tr>\n<tr><td bgcolor='#eeeeec' align='center'>16</td><td bgcolor='#eeeeec' align='center'>0.1256</td><td bgcolor='#eeeeec' align='right'>3728736</td><td bgcolor='#eeeeec'>OC\\AppFramework\\Utility\\SimpleContainer->buildClass( <span>$class = </span><span>class ReflectionClass { public string $name = 'OCA\\\\TestNullableDi\\\\Service\\\\TransitiveService' }</span> )</td><td title='/var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php' bgcolor='#eeeeec'>.../SimpleContainer.php<b>:</b>106</td></tr>\n<tr><td bgcolor='#eeeeec' align='center'>17</td><td bgcolor='#eeeeec' align='center'>0.1256</td><td bgcolor='#eeeeec' align='right'>3730112</td><td bgcolor='#eeeeec'><a href='http://www.php.net/function.array-map' target='_new'>array_map</a>( <span>$callback = </span><span>class Closure { virtual $closure = "$this->OC\\AppFramework\\Utility\\{closure}" }</span>, <span>$array = </span><span>[0 => class ReflectionParameter { public string $name = 'invalidService' }]</span> )</td><td title='/var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php' bgcolor='#eeeeec'>.../SimpleContainer.php<b>:</b>98</td></tr>\n<tr><td bgcolor='#eeeeec' align='center'>18</td><td bgcolor='#eeeeec' align='center'>0.1256</td><td bgcolor='#eeeeec' align='right'>3730592</td><td bgcolor='#eeeeec'>OC\\AppFramework\\Utility\\SimpleContainer->OC\\AppFramework\\Utility\\{closure:/var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php:61-98}( <span>$parameter = </span><span>class ReflectionParameter { public string $name = 'invalidService' }</span> )</td><td title='/var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php' bgcolor='#eeeeec'>.../SimpleContainer.php<b>:</b>98</td></tr>\n<tr><td bgcolor='#eeeeec' align='center'>19</td><td bgcolor='#eeeeec' align='center'>0.1256</td><td bgcolor='#eeeeec' align='right'>3730696</td><td bgcolor='#eeeeec'>OC\\AppFramework\\DependencyInjection\\DIContainer->query( <span>$name = </span><span>'OCA\\\\TestNullableDi\\\\Service\\\\InvalidService'</span>, <span>$autoload = </span><span>TRUE</span> )</td><td title='/var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php' bgcolor='#eeeeec'>.../SimpleContainer.php<b>:</b>74</td></tr>\n<tr><td bgcolor='#eeeeec' align='center'>20</td><td bgcolor='#eeeeec' align='center'>0.1256</td><td bgcolor='#eeeeec' align='right'>3730696</td><td bgcolor='#eeeeec'>OC\\AppFramework\\DependencyInjection\\DIContainer->queryNoFallback( <span>$name = </span><span>'OCA\\\\TestNullableDi\\\\Service\\\\InvalidService'</span> )</td><td title='/var/www/html/lib/private/AppFramework/DependencyInjection/DIContainer.php' bgcolor='#eeeeec'>.../DIContainer.php<b>:</b>412</td></tr>\n<tr><td bgcolor='#eeeeec' align='center'>21</td><td bgcolor='#eeeeec' align='center'>0.1256</td><td bgcolor='#eeeeec' align='right'>3730696</td><td bgcolor='#eeeeec'>OC\\AppFramework\\Utility\\SimpleContainer->query( <span>$name = </span><span>'OCA\\\\TestNullableDi\\\\Service\\\\InvalidService'</span>, <span>$autoload = </span>??? )</td><td title='/var/www/html/lib/private/AppFramework/DependencyInjection/DIContainer.php' bgcolor='#eeeeec'>.../DIContainer.php<b>:</b>440</td></tr>\n<tr><td bgcolor='#eeeeec' align='center'>22</td><td bgcolor='#eeeeec' align='center'>0.1256</td><td bgcolor='#eeeeec' align='right'>3730696</td><td bgcolor='#eeeeec'>OC\\AppFramework\\Utility\\SimpleContainer->resolve( <span>$name = </span><span>'OCA\\\\TestNullableDi\\\\Service\\\\InvalidService'</span> )</td><td title='/var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php' bgcolor='#eeeeec'>.../SimpleContainer.php<b>:</b>124</td></tr>\n<tr><td bgcolor='#eeeeec' align='center'>23</td><td bgcolor='#eeeeec' align='center'>0.1270</td><td bgcolor='#eeeeec' align='right'>3731000</td><td bgcolor='#eeeeec'>OC\\AppFramework\\Utility\\SimpleContainer->buildClass( <span>$class = </span><span>class ReflectionClass { public string $name = 'OCA\\\\TestNullableDi\\\\Service\\\\InvalidService' }</span> )</td><td title='/var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php' bgcolor='#eeeeec'>.../SimpleContainer.php<b>:</b>106</td></tr>\n<tr><td bgcolor='#eeeeec' align='center'>24</td><td bgcolor='#eeeeec' align='center'>0.1271</td><td bgcolor='#eeeeec' align='right'>3731488</td><td bgcolor='#eeeeec'><a href='http://www.php.net/ReflectionClass.newInstanceArgs' target='_new'>newInstanceArgs</a>( <span>$args = </span><span>[0 => NULL]</span> )</td><td title='/var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php' bgcolor='#eeeeec'>.../SimpleContainer.php<b>:</b>98</td></tr>\n<tr><td bgcolor='#eeeeec' align='center'>25</td><td bgcolor='#eeeeec' align='center'>0.1271</td><td bgcolor='#eeeeec' align='right'>3731576</td><td bgcolor='#eeeeec'>OCA\\TestNullableDi\\Service\\InvalidService->__construct( <span>$userId = </span><span>NULL</span> )</td><td title='/var/www/html/lib/private/AppFramework/Utility/SimpleContainer.php' bgcolor='#eeeeec'>.../SimpleContainer.php<b>:</b>98</td></tr>\n"
},
"CustomMessage": "OCA\\TestNullableDi\\Service\\InvalidService::__construct(): Argument #1 ($userId) must be of type string, null given"
}
}
Additional info
The problem originally arose in the forum.
I tracked it down possibly to a combination of caching and the DI with nullable types.
The MWE has multiple cases that might be interesting to implement in tests:
- Keep the version as it is right now (regular case)
- Commenting out the
userId(or making it nullable) in the InvalidService makes the app work in any case. - Uncommenting this line in the InvalidService will hide the error from you but not solve it. This is sort of a bug of a bug.
The reason for the problem is that the DI algorithm traverses the dependency tree down from the top (aka the TransitivePageController class. In the regular case the DI algorithm first evaluates $userId to null and caches this in the Pimple container. Then, DI continues to TransitiveService and InvalidService as expected.
However, when building the InvalidService first all arguments are collected. As the $userId is cached, it is directly reused with the cached null value. Upon executing the controller, PHP checks the argument types and errors out (as it expected a non-nullable string there).
When the $unknownArgument is commented out, the DI bails out throwing a QueryException. This bubbles up until the complete DI branch of TransientService, InvalidService, and its dependencies are (correctly) cut off to null in TransientPageController.
I am pretty sure that commenting out the userId in the TransitivePageConteoller did make the app run without 500 but I can no longer reproduce this in my environment. Maybe there was the OpCache involved. IDK.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with lib/private/AppFramework/Utility/SimpleContainer.php and lib/private/AppFramework/DependencyInjection/DIContainer.php, following the stack trace from nullable dependency resolution to the failing InvalidService construction. Reproduce the issue with the linked test_nullable_di MWE and compare the logged transitive-pub failure with the working transitive endpoint. Done means both pages render the same dummy information without a 500 response.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100