Skip to content

Opening a dynamic route renames the file and strips Astro's route syntax #13

Open

Description

@anthonyb-cc

Opening a dynamic route renames the file and strips Astro's route syntax

Environment

Stacki 0.1.13 (Windows desktop app)
OS Windows 11 Pro — 10.0.26200.9168
Astro 7.2.0
Node 24.14.0
pnpm 10.33.0
Installed at %LOCALAPPDATA%\Programs\Stacki\Stacki.exe

What happens

Opening an Astro dynamic route in Stacki renames the file on disk, removing
the square brackets and dots that Astro uses to declare the route. No edit
and no save are involved — viewing the page is enough:

src/pages/kitchen-sink/[...path].astro   →   src/pages/kitchen-sink/-path-.astro

The transformation looks like [... → - and ] → -, so a named
parameter would go the same way:

[slug].astro        →   -slug-.astro
[...blog].astro     →   -blog-.astro

Git recorded it as a delete plus an untracked file:

 D src/pages/kitchen-sink/[...path].astro
?? src/pages/kitchen-sink/-path-.astro

The file contents were otherwise unchanged — a byte-for-byte match once
line endings are normalised (Stacki also converted LF → CRLF, which is
harmless here but may be worth knowing).

Why this is worse than a broken URL

The obvious effect is that the route stops existing and the page 404s.

The more serious effect is that renaming a dynamic route to a static one
silently disables getStaticPaths, because Astro only consults it for
dynamic routes.

We use that to keep a developer-only page out of production:

// src/pages/kitchen-sink/[...path].astro
export function getStaticPaths() {
  const on = import.meta.env.DEV || process.env.QA_PRIMITIVES === '1'
  return on ? [{ params: { path: undefined } }] : []
}

With the original filename, a production build correctly omits the page.
After the rename, the export is ignored and the page builds and ships:

dist/kitchen-sink/-path-/index.html    64 KB

That file contains a hardcoded http://127.0.0.1:8090 (our local CMS), and
the build exited 0 — no error, no warning. On a real deploy that would
have published an internal page to a client site.

Reproduction

  1. In an Astro project, create src/pages/demo/[...path].astro with a
    getStaticPaths that returns [] unless import.meta.env.DEV.
  2. Confirm astro build produces no dist/demo/.
  3. Open the project in Stacki and open that page. Do not edit it, do not
    save, do not touch anything else.
  4. The file on disk is now src/pages/demo/-path-.astro.
  5. astro build now emits dist/demo/-path-/index.html.

Expected

Filenames should round-trip unchanged. Astro's [param], [...rest] and
[...rest].astro naming is load-bearing routing syntax, not decoration —
rewriting it changes what the project does.

If the current filename can't be represented internally, declining to open
that page would be much safer than opening it under a different name. A
read-only action should not rewrite the project.

Notes

  • This happens on OPEN, not on save. The file is renamed as soon as the
    page is opened in the builder, with no edit made and nothing saved.
  • Only the file I opened was affected. Other dynamic routes in the same
    project (src/pages/[...slug].astro, src/pages/blog/[slug].astro,
    src/pages/blog/[...blog].astro) were untouched.
  • Recovering is straightforward once you notice — git checkout restores
    it — but nothing surfaces the problem at build time, which is what makes
    it easy to ship.

Happy to test a fix or provide any more detail.

Activity

  1. marks-zyz commented on Aug 25, 2026

    @marks-zyz

    Reproduced on macOS (Darwin 25.4.0, arm64) with current main (0.1.20, 136d0b9), running from source (npm run dev), on an Astro 6 project: src/pages/blog/[...slug].astro was rewritten on disk to src/pages/blog/-slug-.astro while the project was being browsed in Stacki. Git recorded it exactly as reported here: a delete plus an untracked file. So this is not Windows-specific.

    I think I found the mechanism. Both sanitize sites live in the renderer, src/panels/PagesPanel.jsx:

    // commitPageRename — line 104
    const base = text.trim().replace(/\.(astro|md)$/i, '').replace(/[^\w-]+/g, '-');
    if (!base || base === stripExt(page.base)) return;
    // commitFolderRename — line 112
    const name = text.trim().replace(/[^\w-]+/g, '-');

    [^\w-] strips Astro's routing syntax — [, ] and the dots of [...rest] — which is how [...slug] becomes -slug-.

    Two details that make it worse than a plain overzealous sanitizer:

    1. The no-op guard compares the sanitized name against the original (base === stripExt(page.base)). For any bracketed route the two can never be equal, so committing the inline-rename field with the pre-filled, unchanged name is enough to trigger a real rename. Since the field commits on Enter/blur, a stray click into the name followed by a click elsewhere rewrites the file — which may be what makes this feel like it happens "on open", with no intentional edit involved.
    2. The same regex on the folder path means no dynamic-route name (file or folder) can ever be entered through this UI either — creating [slug].astro from the panel is impossible.

    A fix that keeps the sanitizer's intent might be: whitelist Astro's route characters (e.g. /[^\w\-\[\]\.@]+/g) and do the "unchanged?" comparison on the raw input before sanitizing, so confirming an existing name is always a no-op regardless of what characters it contains.

    Happy to test a fix on macOS if useful.

  2. domidex01 commented on Aug 25, 2026

    @domidex01

    I open a Pr with the fix in it .
    @flowtricks please review the pr and approve it

  3. added 2 commits that reference this issue on Aug 25, 2026
    a965114
    75217da
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions