{"record":{"id":"37a557c24b1d8c5f","repo":"slimphp/Slim","slug":"missing-data-for-url-segment-s","errorCode":null,"errorMessage":"Missing data for URL segment: %s","messagePattern":"Missing data for URL segment: (.+?)","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"Slim/Routing/RouteParser.php","lineNumber":90,"sourceCode":"                    $segmentName = $segment[0];\n                    break;\n                }\n\n                $segments[] = $data[$segment[0]];\n            }\n\n            /*\n             * If we get to this logic block we have found all the parameters\n             * for the provided $data which means we don't need to continue testing\n             * less specific expressions\n             */\n            if (!empty($segments)) {\n                break;\n            }\n        }\n\n        if (empty($segments)) {\n            throw new InvalidArgumentException('Missing data for URL segment: ' . $segmentName);\n        }\n\n        $url = implode('', $segments);\n        if ($queryParams) {\n            $url .= '?' . http_build_query($queryParams);\n        }\n\n        return $url;\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function urlFor(string $routeName, array $data = [], array $queryParams = []): string\n    {\n        $basePath = $this->routeCollector->getBasePath();\n        $url = $this->relativeUrlFor($routeName, $data, $queryParams);\n","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/slimphp/Slim/blob/80900fb39cafce3ae53b18a2c4f642a122f03095/Slim/Routing/RouteParser.php#L72-L108","documentation":"RouteParser::relativeUrlFor() (used by urlFor() and fullUrlFor()) expands the route pattern into URL segments, filling each {placeholder} from the $data array you pass. It tries every expression variant from most specific (all optional params filled) to least; if no variant can be satisfied — i.e. some required placeholder has no entry in $data — it throws this InvalidArgumentException, naming the first placeholder it could not resolve. The lookup uses array_key_exists, so keys must match placeholder names exactly (case-sensitive); numeric-indexed arrays from older idioms do not work.","triggerScenarios":"Calling $routeParser->urlFor('user.post', ['id' => 1]) for a route pattern like /user/{id}/posts/{postId} — the message will name 'postId'; a typo'd or wrongly-cased data key ('userId' vs 'id'); passing an empty array for a route with any required placeholder; forgetting that only placeholders inside [...] brackets are optional and can be omitted.","commonSituations":"Adding a new required segment to a route pattern but not updating every urlFor() call site; mixed conventions where some code passes positional arrays; template or config files storing route data keyed by old names; optional segments like /archive[/{year}] working without data while /user/{id} requiring it, causing inconsistent expectations across routes.","solutions":["Supply a value for every required placeholder, keyed exactly by its name: urlFor('user.post', ['id' => 1, 'postId' => 9])","Check the data keys against the route pattern for typos and case mismatches — placeholder names are case-sensitive","If the segment is legitimately omittable, make it optional in the pattern: /user/{id}[/{slug}]","Add a pre-flight check that diffs array keys against required placeholders parsed from the pattern before calling urlFor()"],"exampleFix":"// before\n$app->get('/user/{id}/posts/{postId}', PostAction::class)->setName('user.post');\n$url = $routeParser->urlFor('user.post', ['id' => 1]); // throws 'Missing data for URL segment: postId'\n\n// after\n$url = $routeParser->urlFor('user.post', ['id' => 1, 'postId' => 9]);","handlingStrategy":"validation","validationCode":"function requiredRouteParams(string $pattern): array\n{\n    // strip optional segments (square brackets, innermost first)\n    while (preg_match('/\\[[^\\[\\]]*\\]/', $pattern)) {\n        $pattern = (string) preg_replace('/\\[[^\\[\\]]*\\]/', '', $pattern);\n    }\n    preg_match_all('/\\{([^}:]+)(?::[^}]*)?\\}/', $pattern, $m);\n    return $m[1];\n}\n\n$route = $collector->getNamedRoute($name);\n$missing = array_diff(requiredRouteParams($route->getPattern()), array_keys($data));\nif ($missing) {\n    throw new InvalidArgumentException(\n        sprintf('urlFor(%s) is missing: %s', $name, implode(', ', $missing))\n    );\n}\n$url = $routeParser->urlFor($name, $data);","typeGuard":null,"tryCatchPattern":"try {\n    $url = $routeParser->urlFor($name, $data);\n} catch (InvalidArgumentException $e) {\n    // message names the missing placeholder — log it and fall back to a safe default\n    $log->warning($e->getMessage(), ['route' => $name, 'data' => $data]);\n    $url = $defaultPath ?? '/';\n}","preventionTips":["Derive data keys from the pattern itself (or central route metadata) instead of hand-typing them at call sites","When adding a new required segment to a pattern, grep all urlFor()/fullUrlFor() call sites for that route name in the same commit","Remember only placeholders inside [...] are optional; everything else must appear in $data keyed by exact name","Add the requiredRouteParams() pre-flight check in link-builder services that accept dynamic route data"],"tags":["slim","php","routing","url-generation","validation","route-parameters"],"backgroundTag":"missing-route-parameter","analyzedSha":"80900fb39cafce3ae53b18a2c4f642a122f03095","analyzedAt":"2026-08-21T01:41:09.580Z","schemaVersion":2},"datasetVersion":"2026-08-21T03:17:12.404Z"}