rocksdanister/lively · error · UnauthorizedAccessException

Token not found.

Error message

Token not found.

What it means

Thrown by InternalSendAsync when a request requires auth (requireAuth=true, the default) but the token store has no access token at all. It is the pre-flight gate: do not even hit the network without credentials.

Source

Thrown at src/Lively/Lively.Gallery.Client/GalleryClient.cs:296

            var httpResp = await InternalSendAsync(message, isRetry, requireAuth, HttpCompletionOption.ResponseContentRead);
            if (httpResp.StatusCode == HttpStatusCode.Unauthorized)
                throw new UnauthorizedAccessException(ApiErrors.TokensExpired);
            var content = await httpResp.Content.ReadAsStringAsync();
            var response = JsonConvert.DeserializeObject<ApiResponse<T>>(content);
            if (response == null)
                response = new();
            if (response.Errors != null)
            {
                throw new ApiException(response.Errors);
            }
            response.StatusCode = (int)httpResp.StatusCode;
            return response;
        }

        private async Task<HttpResponseMessage> InternalSendAsync(HttpRequestMessage message, bool isRetry, bool requireAuth = true, HttpCompletionOption option = HttpCompletionOption.ResponseContentRead)
        {
            if (requireAuth && Tokens?.AccessToken == null)
                throw new UnauthorizedAccessException("Token not found.");

            if (requireAuth && Tokens?.AccessToken != null)
                message.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", Tokens.AccessToken);
            //The request message was already sent. Cannot send the same request message multiple times.
            var clone = message.Clone();
            var httpResp = await _client.SendAsync(message, option);
            var requireRefreshingTokens = !isRetry && httpResp.StatusCode == HttpStatusCode.Unauthorized;
            if (requireRefreshingTokens)
            {
                var result = await RefreshTokensAsync();

                var tokens = result;
                _tokenStore.Set(tokens.AccessToken, tokens.RefreshToken, _tokenStore.Get().Provider, tokens.Expiration);
                return await InternalSendAsync(clone, true, requireAuth, option);

            }
            clone.Dispose();
            return httpResp;

View on GitHub (pinned to c1036feb66)

Solutions

  1. Guard gallery calls with a login-state check; if not authenticated, route to login instead of calling.
  2. Ensure token store persistence loads correctly on startup before any gallery UI binds.
  3. Catch UnauthorizedAccessException and treat it as 'needs login' uniformly with errors 5/6/8.

Example fix

// before
if (requireAuth && Tokens?.AccessToken == null)
    throw new UnauthorizedAccessException("Token not found.");

// after
if (requireAuth && Tokens?.AccessToken == null)
    throw new UnauthorizedAccessException("NOT_LOGGED_IN");
Defensive patterns

Strategy: validation

Validate before calling

if (string.IsNullOrEmpty(client.Tokens?.AccessToken))
{
    await NavigateToLogin();
    return;
}

Type guard

static bool IsLoggedIn(GalleryClient c) => !string.IsNullOrEmpty(c.Tokens?.AccessToken);

Try / catch

try { await client.SomeAuthedCall(); }
catch (UnauthorizedAccessException ex) when (ex.Message.Contains("Token not found"))
{ await NavigateToLogin(); }

Prevention

When it happens

Trigger: Any SendAsync/DownloadFile call with requireAuth=true while Tokens?.AccessToken is null — i.e. the user is not logged in or the token store is empty.

Common situations: Calling a gallery method before the user signs in; after a logout but the UI still holds stale view-models issuing requests; token store failed to load on startup.

Related errors


AI-assisted analysis of rocksdanister/lively@c1036feb66 (2026-08-13). Data as JSON: /api/errors/d618127967ae0e81. Report an issue: GitHub.