hcengineering/platform · error · Error

Login failed

Error message

Login failed

What it means

getWorkspaceToken resolves a workspace-scoped token by logging in (or using a provided token). After attempting login via the accounts client, if no token could be obtained, it throws 'Login failed'. This means credentials were missing or the login call returned no token.

Source

Thrown at foundations/core/packages/api-client/src/utils.ts:46

export async function getWorkspaceToken (
  url: string,
  options: AuthOptions,
  config?: ServerConfig
): Promise<WorkspaceToken> {
  config ??= await loadServerConfig(url)

  let token: string | undefined

  if ('token' in options) {
    token = options.token
  } else {
    const { email, password } = options
    const loginInfo = await getAccountClient(config.ACCOUNTS_URL).login(email, password)
    token = loginInfo.token
  }

  if (token === undefined) {
    throw new Error('Login failed')
  }

  const ws = await getAccountClient(config.ACCOUNTS_URL, token).selectWorkspace(options.workspace)
  if (ws === undefined) {
    throw new Error('Workspace not found')
  }

  return { endpoint: ws.endpoint, token: ws.token, workspaceId: ws.workspace, info: ws }
}

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Verify email/password credentials are correct and the account exists.
  2. Check config.ACCOUNTS_URL points to a running accounts service.
  3. If passing a token directly, confirm options.token is defined and not expired.
  4. Inspect the login() response shape — an API/version mismatch may drop the token field.
  5. Wrap the call in try/catch and surface a clear credential/config error to the user.

Example fix

// before
const { token } = await getWorkspaceToken({ email, password, workspace })
// after
try {
  const { token } = await getWorkspaceToken({ email, password, workspace })
} catch (err) {
  if (err.message === 'Login failed') {
    throw new Error('Check ACCOUNTS_URL and account credentials: ' + err.message)
  }
  throw err
}
Defensive patterns

Strategy: validation

Validate before calling

if (options.token === undefined && (options.email === undefined || options.password === undefined)) {
  throw new Error('getWorkspaceToken requires either a token or email+password')
}

Type guard

function hasCredentials(o: { token?: string, email?: string, password?: string }): boolean {
  return typeof o.token === 'string' || (typeof o.email === 'string' && typeof o.password === 'string')
}

Try / catch

try {
  const { token } = await getWorkspaceToken(opts)
} catch (err) {
  if (err.message === 'Login failed') {
    showLoginDialog() // re-authenticate
    return
  }
  throw err
}

Prevention

When it happens

Trigger: Calling getWorkspaceToken with options that lack a valid token and where login(email, password) returns undefined/no token — wrong email, wrong password, or account service unreachable/failing.

Common situations: Stale or mistyped credentials in env/config; disabled or deleted account; ACCOUNTS_URL pointing at the wrong service; accounts service returning 2xx with an unexpected payload shape.

Related errors


AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29). Data as JSON: /api/errors/46ad3bc27a7a92a6. Report an issue: GitHub.