Skip to content

Rework the universal [org]/[proj]/[id]/data 301 catch-all (collides with any 3-segment path; permanent 301 wedges browser cache) #959

Description

@softmarshmallow

Summary

editor/app/(workbench)/[org]/[proj]/[id]/route.ts unconditionally 301-redirects
any /{a}/{b}/{c} path to /{a}/{b}/{c}/data:

return NextResponse.redirect(
  editorlink("data", { org, proj, origin, document_id: id }),
  { status: 301 }
);

Because [org]/[proj]/[id] is a catch-all 3-segment matcher, this fires for
any unmatched 3-segment path — not just real projects — and the redirect is a
permanent, browser-cacheable 301. That combination is a recurring footgun.

Why it's a problem

  1. Collides with any 3-segment path. A missing static asset under a 3-segment
    URL (e.g. /templates/slides/index.json) falls through to this route and is
    redirected to …/data instead of returning a clean 404.
  2. /…/<file>/data → 500, not 404. The redirected path is then resolved as a
    static file: Next stats public/…/<file>/data, which throws ENOTDIR when
    <file> is a real file (Next's static handler only anticipates ENOENT) →
    unhandled 500.
  3. Permanent 301 = cached wedge. The 301 carries no Cache-Control, so
    Chromium/Electron caches it indefinitely. Once a client sees it (while the
    asset was momentarily missing), it keeps following the cached redirect to
    …/data → 500 without ever re-requesting the now-present asset. Only a
    cache clear recovers it.

Evidence

  • Bit the desktop slides gallery in feat(desktop): slides template workflow for agent-authored decks #949: a not-yet-materialized
    /templates/slides/index.json → 301 → …/dataENOTDIR 500, and then the
    cached 301 kept the error alive in the desktop renderer after the file existed
    (recovered only by clearing the network cache).
  • This is not the first time this catch-all /data redirect has produced
    surprising behavior — it's a recurring bad design, not a one-off.

The ask (later, focused — does not block current work)

Carefully rework or drop the universal /data redirect. Directions to weigh:

  • Scope the match to real projects — validate that org/proj/id resolve
    before redirecting, so arbitrary 3-segment paths fall through to a normal 404
    instead of being absorbed.
  • If the redirect stays, make it non-permanent (302/307) so a stale mistake
    can't wedge a browser cache.
  • Avoid the catch-all route handler entirely for "bare project URL → default
    tab" — e.g. render the default tab, or redirect from inside the already-
    validated layout.tsx (which does the org/proj/doc lookups anyway).

Care needed: this drives the real /{org}/{proj}/{id}/{org}/{proj}/{id}/data
behavior for actual projects. The fix must preserve that while removing the
catch-all collision — a focused pass, not a drive-by.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions