theonedev/onedev · error · UnauthenticatedException

Unauthenticated

Error message

Unauthenticated

What it means

This endpoint returns a description of pull request query syntax for AI tooling. Like the other TodResource query-description endpoints, it throws UnauthenticatedException when SecurityUtils.getUser() is null, i.e. the request carries no authenticated user.

Solutions

  1. Send authentication with the request (login session cookie, basic auth, or access token).
  2. Re-authenticate if the previous session expired, then retry the call.
  3. Confirm the client (AI tool runner) is configured with OneDev credentials/URL that include authentication.
  4. Check server logs to confirm the request arrives without a user principal, indicating the client is not sending cookies/tokens.

Example fix

// before
fetch(base + '/~ai/get-pull-request-query-description');
// after
fetch(base + '/~ai/get-pull-request-query-description', { headers: { Authorization: 'Bearer ' + token } });
Defensive patterns

Strategy: validation

Validate before calling

if (!authClient) throw new Error('get-pull-request-query-description requires an authenticated client');

Type guard

const isAuthError = (e) => e?.status === 401 || /unauthenticated/i.test(e?.message ?? '');

Try / catch

try { return await client.get('/~ai/get-pull-request-query-description'); } catch (e) { if (isAuthError(e)) { await client.login(creds); return client.get('/~ai/get-pull-request-query-description'); } throw e; }

Prevention

When it happens

Trigger: GET /get-pull-request-query-description without a valid logged-in session or credentials.

Common situations: An AI agent invoking the PR-query-description tool anonymously; expired session; missing Authorization header when calling from external code.

Understand the failure class

Related errors


AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06). Data as JSON: /api/errors/8ce6a9d0e4a33c7f. Report an issue: GitHub.

Appendix: source

Thrown at server-core/src/main/java/io/onedev/server/ai/TodResource.java:328

    public String getIssueQueryDescription() {
        if (SecurityUtils.getUser() == null)
            throw new UnauthenticatedException();
        return escapeHtml5(QueryDescriptions.getIssueQueryDescription());
    }

    @Path("/get-build-query-description")
    @GET
    public String getBuildQueryDescription() {
        if (SecurityUtils.getUser() == null)
            throw new UnauthenticatedException();
        return escapeHtml5(QueryDescriptions.getBuildQueryDescription());
    }

    @Path("/get-pull-request-query-description")
    @GET
    public String getPullRequestQueryDescription() {
        if (SecurityUtils.getUser() == null)
            throw new UnauthenticatedException();
        return escapeHtml5(QueryDescriptions.getPullRequestQueryDescription());
    }

    @Path("/get-project-query-description")
    @GET
    public String getProjectQueryDescription() {
        if (SecurityUtils.getUser() == null)
            throw new UnauthenticatedException();
        return escapeHtml5(QueryDescriptions.getProjectQueryDescription());
    }

    @Path("/get-valid-issue-fields")
    @GET
    public Map<String, Object> getValidIssueFields() {
        if (SecurityUtils.getUser() == null)
            throw new UnauthenticatedException();
        var issueFields = new HashMap<String, Object>();
        for (var field: settingService.getIssueSetting().getFieldSpecs()) {

View on GitHub (pinned to d44925c47c)