Skip to content

fix(components): show server-supplied error messages on the sign-in form - #2396

Merged
dividedmind merged 1 commit into
mainfrom
feat/handle-otp-denials
Sep 4, 2026
Merged

fix(components): show server-supplied error messages on the sign-in form#2396
dividedmind merged 1 commit into
mainfrom
feat/handle-otp-denials

Conversation

@dividedmind

Copy link
Copy Markdown
Collaborator

The activation endpoints can answer a 4xx with a body of the form {"error": {"code": ..., "message": ...}}, explaining in the user's terms why the request was rejected. The form discarded it and always displayed its own guess -- "Invalid email address, please try again." -- which is misleading whenever the request failed for any reason other than a malformed field, and leaves the user with no idea what to do next.

Prefer the server's message when a 4xx carries one. The error code is deliberately ignored: the message is the part written for the user, and matching on codes would leave every code the server adds later falling back to the misleading wording. Every other shape keeps the existing text -- a non-JSON body, a missing, blank or non-string message, and any 5xx, whose body is an internal error or a proxy's HTML rather than anything worth showing.

Also stop clearing the email input on error. Making the user retype an address after a network blip serves no purpose, and blanking the field hides the very address the message is about. The verification code still clears, and "try again" still resets both.

The two new Storybook stories drive these paths through a stubbed fetch, so the error handling can be exercised without a server.

Assisted-by: Claude:claude-opus-5[1m]

@dividedmind
dividedmind requested review from kgilpin and a lite review from Copilot September 2, 2026 15:29
@dividedmind dividedmind self-assigned this Sep 2, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The Storybook title change likely breaks existing Cypress navigation by story ID, and completeActivation() still doesn’t clear verificationCode on network/exception failures despite the stated behavior.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Updates the components sign-in/activation flow to prefer user-facing error messages returned by the activation API on 4xx responses, and adjusts UX so the email address is not cleared on error. Adds unit/e2e coverage and Storybook stories to exercise the new denial-message paths without requiring a live server.

Changes:

  • Prefer server-supplied error.message for 4xx responses in activation + verification flows (fallback to existing client messages otherwise).
  • Keep the email input value on failure (while still clearing verification code where applicable).
  • Add unit tests, Cypress e2e coverage, and Storybook stories for the denial-message scenarios via stubbed fetch.
File summaries
File Description
packages/components/tests/unit/SignIn.spec.js Adds unit coverage for server-supplied error messages + email retention on errors.
packages/components/tests/e2e/specs/sidebarSignIn.spec.js Adds Cypress coverage for displaying server-supplied denial messages in both activation and verification.
packages/components/src/stories/SignIn.stories.js Adds Storybook stories that stub fetch to simulate denied activation/verification responses.
packages/components/src/components/SignIn.vue Implements serverMessage() and updates error handling to prefer server messages on 4xx while keeping email input on failure.
Review details

Suppressed comments (1)

packages/components/src/components/SignIn.vue:277

  • completeActivation() clears verificationCode for HTTP error responses, but on outright request failures (the catch branch) it leaves the verification code intact. The PR description says the verification code still clears on error; this currently doesn’t happen for network/exception failures.
          this.error = GENERIC_ERROR_MSG;
        }
      } catch (error) {
        this.error = GENERIC_ERROR_MSG;
        this.submitted = false;
  • Files reviewed: 4/4 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread packages/components/src/stories/SignIn.stories.js
Comment thread packages/components/src/stories/SignIn.stories.js
The activation endpoints can answer a 4xx with a body of the form
{"error": {"code": ..., "message": ...}}, explaining in the user's terms
why the request was rejected. The form discarded it and always displayed
its own guess -- "Invalid email address, please try again." -- which is
misleading whenever the request failed for any reason other than a
malformed field, and leaves the user with no idea what to do next.

Prefer the server's message when a 4xx carries one. The error code is
deliberately ignored: the message is the part written for the user, and
matching on codes would leave every code the server adds later falling
back to the misleading wording. Every other shape keeps the existing
text -- a non-JSON body, a missing, blank or non-string message, and any
5xx, whose body is an internal error or a proxy's HTML rather than
anything worth showing.

Also stop clearing the email input on error. Making the user retype an
address after a network blip serves no purpose, and blanking the field
hides the very address the message is about. The verification code still
clears, and "try again" still resets both.

The two new Storybook stories drive these paths through a stubbed fetch,
so the error handling can be exercised without a server.

Assisted-by: Claude:claude-opus-5[1m]
@dividedmind
dividedmind force-pushed the feat/handle-otp-denials branch from b70c862 to cd897e6 Compare September 2, 2026 15:39
@dividedmind
dividedmind merged commit a9a7363 into main Sep 4, 2026
26 checks passed
@dividedmind
dividedmind deleted the feat/handle-otp-denials branch September 4, 2026 04:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants