{"record":{"id":"bc9ae1d01cfb4c6f","repo":"rwf2/Rocket","slug":"earlytrailing","errorCode":"EarlyTrailing","errorMessage":"unexpected text after trailing parameter","messagePattern":"unexpected text after trailing parameter","errorType":"validation","errorClass":"rocket_codegen::param::Error","httpStatus":null,"severity":"error","filePath":"core/codegen/src/attribute/param/parse.rs","lineNumber":102,"sourceCode":"                .emit_as_item_tokens();\n        }\n\n        Ok(Parameter::Static(Name::new(segment, source_span)))\n    }\n\n    pub fn parse_many<P: Part>(\n        source: &str,\n        source_span: Span,\n    ) -> impl Iterator<Item = Result<Self, Error<'_>>> {\n        let mut trailing: Option<(&str, Span)> = None;\n\n        // We check for empty segments when we parse an `Origin` in `FromMeta`.\n        source.split(P::DELIMITER)\n            .filter(|s| !s.is_empty())\n            .enumerate()\n            .map(move |(i, segment)| {\n                if let Some((trail, span)) = trailing {\n                    let error = Error::new(trail, span, ErrorKind::EarlyTrailing)\n                        .source(source, source_span);\n\n                    return Err(error);\n                }\n\n                let segment_span = subspan(segment, source, source_span);\n                let mut parsed = Self::parse::<P>(segment, segment_span)\n                    .map_err(|e| e.source(source, source_span))?;\n\n                if let Some(ref mut d) = parsed.dynamic_mut() {\n                    if d.trailing {\n                        trailing = Some((segment, segment_span));\n                    }\n\n                    d.index = i;\n                }\n\n                Ok(parsed)","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/rwf2/Rocket/blob/3a54d079aef060a8f732bd04ea54b0581a604087/core/codegen/src/attribute/param/parse.rs#L84-L120","documentation":"Compile-time error from Rocket's codegen: a trailing parameter <name..> was declared, but another segment follows it in the same route. In parse_many, once a segment with trailing=true is seen, the iterator latches it and every subsequent (non-empty) segment returns ErrorKind::EarlyTrailing with the trailing segment's span. A trailing parameter by definition consumes the rest of the path/query, so nothing may come after it.","triggerScenarios":"#[get(\"/<path..>/edit\")] — segment after a trailing param; #[get(\"/a/<rest..>/b\")]; also in query strings: /search?<params..>&<page>.","commonSituations":"Adding a suffix route segment (like /edit or a format extension) after an existing catch-all; merging two routes and forgetting to remove a trailing catch-all; assuming <rest..> behaves like a glob that can be followed by literal text.","solutions":["Move the trailing parameter to the very end: #[get(\"/edit/<path..>\")] instead of #[get(\"/<path..>/edit\")]","Or make the parameter non-trailing (<path>) if it should match a single segment only","Or split into two routes if the suffix routes need distinct handlers"],"exampleFix":"// before\n#[get(\"/<path..>/edit\")]\nfn edit(path: Path<String>) { }\n\n// after\n#[get(\"/edit/<path..>\")]\nfn edit(path: Path<String>) { }","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep <name..> as the last segment of the route, always","Use <name> (single segment) when a literal suffix must follow","Split into multiple routes when suffix semantics differ"],"tags":["rust","rocket","proc-macro","codegen","compile-time","trailing-parameter"],"backgroundTag":"trailing-parameter-misuse","analyzedSha":"3a54d079aef060a8f732bd04ea54b0581a604087","analyzedAt":"2026-08-16T22:01:48.395Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}