Not all mandatory fields in episode creation are marked so?
### Describe the bug Failing to fill new episode title in creation form incorrectly does not show form validation error, instead showing HTTP 50x. ### Steps to reproduce 1. Go to admin->some podcast->new episode 2. Only select audio file (omit title!) ### Expected behavior Form validation fails, telling you to fill the title. ### Actual behavior 50x in routing (?). ### Relevant logs and/or screenshots Dump from `CI_ENVIRONMENT="development"` run: ``` CodeIgniter\Router\Exceptions\RouterException Router.invalidParameterType SYSTEMPATH/Router/RouteCollection.php at line 1378 1371 1372 // Remove `(:` and `)` when $placeholder is a placeholder. 1373 $placeholderName = substr($placeholder, 2, -1); 1374 // or maybe $placeholder is not a placeholder, but a regex. 1375 $pattern = $this->placeholders[$placeholderName] ?? $placeholder; 1376 1377 if (! preg_match('#^' . $pattern . '$#u', $params[$index])) { 1378 throw RouterException::forInvalidParameterType(); 1379 } 1380 1381 // Ensure that the param we're inserting matches 1382 // the expected param type. 1383 $pos = strpos($from, $placeholder); 1384 $from = substr_replace($from, $params[$index], $pos, strlen($placeholder)); 1385 } Backtrace Server Request Response Files Memory SYSTEMPATH/Router/RouteCollection.php : 1378 — CodeIgniter\Router\Exceptions\RouterException::forInvalidParameterType () 1371 1372 // Remove `(:` and `)` when $placeholder is a placeholder. 1373 $placeholderName = substr($placeholder, 2, -1); 1374 // or maybe $placeholder is not a placeholder, but a regex. 1375 $pattern = $this->placeholders[$placeholderName] ?? $placeholder; 1376 1377 if (! preg_match('#^' . $pattern . '$#u', $params[$index])) { 1378 throw RouterException::forInvalidParameterType(); 1379 } 1380 1381 // Ensure that the param we're inserting matches 1382 // the expected param type. 1383 $pos = strpos($from, $placeholder); 1384 $from = substr_replace($from, $params[$index], $pos, strlen($placeholder)); 1385 } SYSTEMPATH/Router/RouteCollection.php : 1169 — CodeIgniter\Router\RouteCollection->buildReverseRoute () 1162 // Named routes get higher priority. 1163 foreach ($this->routesNames as $verb => $collection) { 1164 if (array_key_exists($search, $collection)) { 1165 $routeKey = $collection[$search]; 1166 1167 $from = $this->routes[$verb][$routeKey]['from']; 1168 1169 return $this->buildReverseRoute($from, $params); 1170 } 1171 } 1172 1173 // Add the default namespace if needed. 1174 $namespace = trim($this->defaultNamespace, '\\') . '\\'; 1175 if ( 1176 substr($search, 0, 1) !== '\\' SYSTEMPATH/Common.php : 978 — CodeIgniter\Router\RouteCollection->reverseRoute () 971 * @param int|string ...$params One or more parameters to be passed to the route. 972 * The last parameter allows you to set the locale. 973 * 974 * @return false|string The route (URI path relative to baseURL) or false if not found. 975 */ 976 function route_to(string $method, ...$params) 977 { 978 return Services::routes()->reverseRoute($method, ...$params); 979 } 980 } 981 982 if (! function_exists('session')) { 983 /** 984 * A convenience method for accessing the session instance, 985 * or an item that has been set in the session. SYSTEMPATH/Helpers/url_helper.php : 482 — route_to() APPPATH/Entities/Episode.php : 454 — url_to() APPPATH/Entities/Episode.php : 466 — App\Entities\Episode->getLink () 459 return $theme 460 ? url_to('embed-theme', esc($this->getPodcast()->handle), esc($this->attributes['slug']), $theme) 461 : url_to('embed', esc($this->getPodcast()->handle), esc($this->attributes['slug'])); 462 } 463 464 public function setGuid(?string $guid = null): static 465 { 466 $this->attributes['guid'] = $guid === null ? $this->getLink() : $guid; 467 468 return $this; 469 } 470 471 public function getPodcast(): ?Podcast 472 { 473 return (new PodcastModel())->getPodcastById($this->podcast_id); SYSTEMPATH/Entity/Entity.php : 485 — App\Entities\Episode->setGuid () 478 $this->{'_' . $method}($value); 479 480 return; 481 } 482 483 // If a "`set` + $key" method exists, it is also a setter. 484 if (method_exists($this, $method) && $method !== 'setAttributes') { 485 $this->{$method}($value); 486 487 return; 488 } 489 490 // Otherwise, just the value. This allows for creation of new 491 // class properties that are undefined, though they cannot be 492 // saved. Useful for grabbing values through joins, assigning SYSTEMPATH/Entity/Entity.php : 152 — CodeIgniter\Entity\Entity->__set () 145 public function fill(?array $data = null) 146 { 147 if (! is_array($data)) { 148 return $this; 149 } 150 151 foreach ($data as $key => $value) { 152 $this->__set($key, $value); 153 } 154 155 return $this; 156 } 157 158 /** 159 * General method that will return all public and protected values SYSTEMPATH/Entity/Entity.php : 133 — CodeIgniter\Entity\Entity->fill () 126 /** 127 * Allows filling in Entity parameters during construction. 128 */ 129 public function __construct(?array $data = null) 130 { 131 $this->syncOriginal(); 132 133 $this->fill($data); 134 } 135 136 /** 137 * Takes an array of key/value pairs and sets them as class 138 * properties, using any `setCamelCasedProperty()` methods 139 * that may or may not exist. 140 * ROOTPATH/modules/Admin/Controllers/EpisodeController.php : 195 — CodeIgniter\Entity\Entity->__construct () 188 ->withInput() 189 ->with('error', lang('Episode.messages.sameSlugError')); 190 } 191 192 $db = db_connect(); 193 $db->transStart(); 194 195 $newEpisode = new Episode([ 196 'created_by' => user_id(), 197 'updated_by' => user_id(), 198 'podcast_id' => $this->podcast->id, 199 'title' => $this->request->getPost('title'), 200 'slug' => $this->request->getPost('slug'), 201 'guid' => null, 202 'audio' => $this->request->getFile('audio_file'), ROOTPATH/modules/Admin/Controllers/EpisodeController.php : 64 — Modules\Admin\Controllers\EpisodeController->attemptCreate () 57 58 $this->episode = $episode; 59 60 unset($params[1]); 61 unset($params[0]); 62 } 63 64 return $this->{$method}(...$params); 65 } 66 67 public function list(): string 68 { 69 /** @var ?string $query */ 70 $query = $this->request->getGet('q'); 71 SYSTEMPATH/CodeIgniter.php : 941 — Modules\Admin\Controllers\EpisodeController->_remap () 934 */ 935 protected function runController($class) 936 { 937 // This is a Web request or PHP CLI request 938 $params = $this->router->params(); 939 940 $output = method_exists($class, '_remap') 941 ? $class->_remap($this->method, ...$params) 942 : $class->{$this->method}(...$params); 943 944 $this->benchmark->stop('controller'); 945 946 return $output; 947 } 948 SYSTEMPATH/CodeIgniter.php : 502 — CodeIgniter\CodeIgniter->runController () 495 if (! method_exists($controller, '_remap') && ! is_callable([$controller, $this->method], false)) { 496 throw PageNotFoundException::forMethodNotFound($this->method); 497 } 498 499 // Is there a "post_controller_constructor" event? 500 Events::trigger('post_controller_constructor'); 501 502 $returned = $this->runController($controller); 503 } else { 504 $this->benchmark->stop('controller_constructor'); 505 $this->benchmark->stop('controller'); 506 } 507 508 // If $returned is a string, then the controller output something, 509 // probably a view, instead of echoing it directly. Send it along SYSTEMPATH/CodeIgniter.php : 361 — CodeIgniter\CodeIgniter->handleRequest () 354 355 $this->getRequestObject(); 356 $this->getResponseObject(); 357 358 $this->spoofRequestMethod(); 359 360 try { 361 $this->response = $this->handleRequest($routes, config(Cache::class), $returnResponse); 362 } catch (ResponsableInterface|DeprecatedRedirectException $e) { 363 $this->outputBufferingEnd(); 364 if ($e instanceof DeprecatedRedirectException) { 365 $e = new RedirectException($e->getMessage(), $e->getCode(), $e); 366 } 367 368 $this->response = $e->getResponse(); FCPATH/index.php : 85 — CodeIgniter\CodeIgniter->run () 78 *--------------------------------------------------------------- 79 * LAUNCH THE APPLICATION 80 *--------------------------------------------------------------- 81 * Now that everything is set up, it's time to actually fire 82 * up the engines and make this app do its thang. 83 */ 84 85 $app->run(); 86 87 // Save Config Cache 88 // $factoriesCache->save('config'); 89 // ^^^ Uncomment this line if you want to use Config Caching. 90 91 // Exits the application, setting the exit code for CLI-based applications 92 // that might be watching. Displayed at 19:17:29pm — PHP: 8.2.14 — CodeIgniter: 4.4.3 -- Environment: development ``` ### Context - Castopod: 1.7.3 - OS: Debian 11 - Browser: Firefox 121 - Web server: NGINX - Yunohost 11.2.8 with Castopod 1.7.3\~ynh2 ### Possible fixes Works when I fill title field (i.e. missing description properly causes validation error).
issue