You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Root route under paths.base always redirects to a trailing slash, ignoring trailingSlash: "never" #17391
With paths.base set, a request for the base root (/some-path) always gets a 308 to /some-path/, even when the root layout exports trailingSlash = "never". Every other route follows the option, so the root is the only URL in the app that ends in a slash.
The rule is hard-coded in src/runtime/server/respond.js:
// if `paths.base === '/a/b/c`, then the root route is `/a/b/c/`,// regardless of the `trailingSlash` route optionif(url.pathname===base||url.pathname===base+'/'){trailing_slash='always';}elseif(page_nodes){
I'd expect the root to follow the same trailingSlash value as everything else: "never" serves /some-path and redirects /some-path/ to it, "always" keeps the current behavior. The default could stay "always" for the root if changing it would break existing apps, but there's currently no way to opt out at all.
#13310 was closed by #16788, which only fixed how the prerendered root is excluded from Netlify's edge function, and the runtime rule above is unchanged.
Cloned https://github.com/firatciftci/sveltekit-base-root-trailing-slash; ran pnpm install, pnpm build, and node build with original locked dependencies.: Installation and build succeeded with Kit 3.0.1, adapter-node 6.0.0, Svelte 5.57.2, and Vite 8.3.3. HEAD /app returned 308 with location ./app/. HEAD /app/about/ returned 308 with location ../about. agent-browser confirmed /app becomes /app/ and renders the root page.
Changed the supplied app's Kit dependency and override to file:../../repos/kit/packages/kit, added Vite fs.allow, reinstalled and rebuilt.: Installation and build succeeded. The exact same request and browser scenario reproduced the unwanted /app/ redirect against current source at a06817e.
Created triage/kit-17391-base-root-trailing-slash and reduced the report into options-2 with root-layout trailingSlash = 'never' and a request regression test.: DEV=true pnpm exec playwright test --grep 'honors trailingSlash never at the base root' failed in both JS modes: expected 200, received 308. The built-preview run also failed in both modes, receiving 307 from a separate preview root redirect.
Inspected actual SSR HTML from the supplied app and evaluated its import URLs and hydration base at slashful versus slashless roots.: Current ./_app/immutable/entry imports resolve correctly under /app/ but incorrectly under /app, dropping the base. The hydration base expression also becomes empty at /app. Prerender output still emits index.html for either root form, so restoring a './app' relative prefix would reintroduce the directory-index bug fixed by PR always add trailing slash to base path #9343.
Recorded inquiry and decision in /workspace/notes.txt and stopped before editing product code.: Only the diagnostic layout and failing test remain uncommitted in packages/kit/test/apps/options-2. No product patch, full-suite verification, review, commit, or push was performed.
Why I stopped
The bug is confirmed, but removing the respond.js special case is not a safe complete fix. The client router and preview server independently enforce the same slash, while relative SSR links, client asset imports, and hydration-base calculation depend on it. Its original purpose remains active: prerendered roots are directory-index files, and slashless-root relative prefixes break those files when served at /app/ or /app/index.html. Supporting the requested behavior safely needs an explicit policy for slashless SSR roots versus prerendered directory roots, coordinated with rendering/path resolution and prerendered serving/adapter behavior. A server-only removal breaks the supplied app's default relative paths; a universal './app' prefix reintroduces the historical static-output regression; a nonprerender-only exception leaves root options inconsistent across rendering modes. I could not establish a safe, verified change within this session, so stopped without committing or pushing.
Activity
svelte-triage-bot commentedon Oct 9, 2026
I reproduced the issue, but could not produce a safe, verified fix.
What I tried
paths.basealways redirects to a trailing slash, ignoringtrailingSlash: "never"#17391 and comments through the GitHub connection; read AGENTS.md, CONTRIBUTING.md, and page-options documentation.: Issue is open with no comments. Documentation describes never/always/ignore but does not explain the base-root exception.paths.baseis set #10763 and fix: respect trailing slash option when navigating from the root page of the basepath #11388 aligned preview/client behavior. fix: resolve all client paths through one base/assets rule #17056 preserves relative rendering and server-route-resolution paths behind proxies. The issue's cited fix: don't record a trailing slash for a prerendered root page combined with a base path #16472 is closed, not merged, and addresses recorded prerender paths rather than runtime normalization.Why I stopped
The bug is confirmed, but removing the respond.js special case is not a safe complete fix. The client router and preview server independently enforce the same slash, while relative SSR links, client asset imports, and hydration-base calculation depend on it. Its original purpose remains active: prerendered roots are directory-index files, and slashless-root relative prefixes break those files when served at /app/ or /app/index.html. Supporting the requested behavior safely needs an explicit policy for slashless SSR roots versus prerendered directory roots, coordinated with rendering/path resolution and prerendered serving/adapter behavior. A server-only removal breaks the supplied app's default relative paths; a universal './app' prefix reintroduces the historical static-output regression; a nonprerender-only exception leaves root options inconsistent across rendering modes. I could not establish a safe, verified change within this session, so stopped without committing or pushing.
teemingc commentedon Oct 12, 2026
@dummdidumm was there a reason the base path root page must end in a trailing slash?