usememos/memos · error · Error
Failed to link account. Please sign in to Memos again and re
Error message
Failed to link account. Please sign in to Memos again and retry.
What it means
Thrown in AuthCallback's link flow when the OAuth provider redirected back with flowMode === "link" but currentUser?.name is falsy. Linking an identity requires an authenticated Memos session (the parent resource for createLinkedIdentity); if the session expired or tokens were lost during the round-trip to the IdP, there is no parent user to attach the identity to.
Source
Thrown at web/src/pages/AuthCallback.tsx:87
// Validate OAuth state (CSRF protection) and retrieve PKCE code_verifier
const validatedState = validateOAuthState(state);
if (!validatedState) {
setState({
loading: false,
errorMessage: "Failed to authorize. Invalid or expired state parameter. This may indicate a CSRF attack attempt.",
});
return;
}
const { flowMode, identityProviderName, returnUrl, linkingUserName, codeVerifier } = validatedState;
const redirectUri = absolutifyLink("/auth/callback");
handledRef.current = true;
(async () => {
try {
if (flowMode === "link") {
if (!currentUser?.name) {
throw new Error("Failed to link account. Please sign in to Memos again and retry.");
}
if (linkingUserName && currentUser.name !== linkingUserName) {
throw new Error("The signed-in user changed before the OAuth callback completed. Please retry linking from account settings.");
}
await userServiceClient.createLinkedIdentity({
parent: currentUser.name,
idpName: identityProviderName,
code,
redirectUri,
codeVerifier: codeVerifier || "",
});
} else {
const response = await authServiceClient.signIn({
credentials: {
case: "ssoCredentials",
value: {
idpName: identityProviderName,
code,View on GitHub (pinned to 14d757ce1f)
Solutions
- Sign in to Memos again in the same browser, then re-run the linking flow from account settings.
- Verify the Memos session survived: check web/src/auth-state.ts token storage and that the auth interceptor can refresh the access token.
- Ensure the OAuth redirect lands in the same browser profile/tab context where linking started (no 'open in new profile' links).
- If it recurs, inspect DevTools > Application for the auth tokens and confirm the IdP redirect_uri matches the origin.
Defensive patterns
Strategy: validation
Validate before calling
// before starting a link flow
if (!currentUser?.name) {
showError("Sign in to Memos before linking an account.");
return;
}
// embed the user into the state so the callback can verify
startLinkFlow(currentUser.name); Type guard
const canLink = (user: { name?: string } | null | undefined): user is { name: string } =>
typeof user?.name === "string" && user.name.length > 0; Try / catch
catch (e) {
if (e instanceof Error && e.message.includes("Failed to link account")) {
await signOut(); // clear partial state
navigate("/auth", { state: { reason: "relink" } });
}
} Prevention
- Require an authenticated session before exposing the 'link account' action.
- Store linkingUserName in OAuth state (the code already does) and verify it at callback.
- Keep the Memos tab open and active for the whole IdP round-trip.
When it happens
Trigger: User starts 'link account' from settings, gets redirected to the IdP, and meanwhile the Memos access/refresh token expires or auth-state storage is cleared; on callback, currentUser is null/undefined while stored state says flowMode === "link". Also occurs when the callback opens in a different browser profile or the auth BroadcastChannel state was reset.
Common situations: Long IdP login pages (password manager, 2FA) outlasting the Memos session; refresh token revoked; tokens stored per-tab and callback lands in a new tab; clock skew expiring the access token early.
Related errors
- The signed-in user changed before the OAuth callback complet
- Failed to initialize OAuth flow
- Unauthenticated
- CodeUnauthenticated
- password authentication for regular users cannot be disabled
AI-assisted analysis of usememos/memos@14d757ce1f (2026-08-15).
Data as JSON: /api/errors/826edb772a63c082.
Report an issue: GitHub.