Skip to content

console: copied invitation link is unusable — buildAcceptUrl rebuilds the trailing-dot host that resolveHomeUrl already retired #4472

Description

@hotlong

Moved from objectstack-ai/objectstack#8090 at triage (file-at-destination: the fix is entirely in this repo). Filed 2026-08-12 by @baozhoutao from a multi-org console walkthrough, original grading priority:p1. Batch siblings: objectstack-ai/objectstack#8091 #8092 #8093 #8094 (see that thread).

Copying an invitation link from the workspace Invitations tab yields a URL that cannot be opened. The recipient of an invitation therefore has no working way in.

Repro

  1. Multi-org runtime, zh console, sign up and create a workspace (owner).
  2. Users → Invite user → invite lisi@acme-test.com as member.
  3. Workspace switcher → Manage membersInvitations tab → click Copy invitation link.
  4. Paste the clipboard content.

Actual

http://localhost:8080./accept-invitation/bgn1XAfRuCQUS1l9NBqOMGgJDUYm5l56

Two defects in one string:

  • trailing-dot hostlocalhost:8080. (the port is followed by .);
  • the console mount is missing — the console is served under /_console/, and GET /accept-invitation/ (dot removed) is answered by the server with {"error":"Not found"}.

The only URL that renders the accept page is http://localhost:8080/_console/accept-invitation/<id> — verified working, the page loads and the invitation can be accepted.

Expected

The copied link is the one the recipient can open: <console mount>accept-invitation/<id>.

Cause

buildAcceptUrl rebuilds the URL from import.meta.env.BASE_URL, which is '.' in a portable (base: './') build:

// packages/app-shell/src/console/organizations/manage/InvitationsPage.tsx:32functionbuildAcceptUrl(invitationId: string): string{constbase=(import.meta asany).env?.BASE_URL??'/';constnormalized=base.endsWith('/') ? base : `${base}/`;return`${window.location.origin}${normalized}accept-invitation/${invitationId}`;}

Duplicated verbatim in packages/app-shell/src/console/organizations/manage/InviteMemberDialog.tsx:39 (the "share link" view of the invite dialog), so the freshly-created-invitation link is broken the same way.

This is the exact failure mode resolveHomeUrl.ts was written to retire — its header documents it:

${origin}${import.meta.env.BASE_URL}home broke portable builds (base: './'), producing https://host./home — trailing-dot host.

Suggested fix

Drop both local buildAcceptUrl copies and call the existing mount-aware helper:

import{resolveConsoleUrl}from'../resolveHomeUrl';consturl=resolveConsoleUrl(`accept-invitation/${invitationId}`);

resolveConsoleUrl resolves against the deployment mount, which is what both WorkspaceSwitcher and OrganizationsPage already use for full-page navigations. A regression test asserting the copied URL contains no :. and starts with the console mount would pin it.

Environment

Local dev server http://localhost:8080, multi-org enabled, zh locale, observed 2026-08-12. The server was started by the maintainer and its exact commit is not verified; the source quoted above is the objectui main checkout at filing time.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions