coleam00/Archon · error

Authentication failed for ${owner}/${repo}. Check GITEA_TOKE

Error message

Authentication failed for ${owner}/${repo}. Check GITEA_TOKEN permissions.

What it means

When the clone operation reports error code 'permission_denied', ensureRepoReady throws this message indicating the GITEA_TOKEN failed authentication or lacks permission for owner/repo. It is distinguished from 'not_a_repo' so operators know the repository exists but the credentials were rejected.

Source

Thrown at packages/adapters/src/community/forge/gitea/adapter.ts:553

    // Parse URL to get host for authenticated clone
    const urlObj = new URL(this.baseUrl);
    const repoUrl = `${urlObj.protocol}//${urlObj.host}/${owner}/${repo}.git`;

    const cloneResult = await cloneRepository(repoUrl, toRepoPath(repoPath), {
      token: process.env.GITEA_TOKEN,
    });

    if (!cloneResult.ok) {
      getLog().error({ owner, repo, repoPath, error: cloneResult.error }, 'repo_clone_failed');

      if (cloneResult.error.code === 'not_a_repo') {
        throw new Error(
          `Repository ${owner}/${repo} not found or is private. Check repository access.`
        );
      }
      if (cloneResult.error.code === 'permission_denied') {
        throw new Error(
          `Authentication failed for ${owner}/${repo}. Check GITEA_TOKEN permissions.`
        );
      }
      const unknownMsg = (cloneResult.error as { message?: string }).message ?? 'unknown error';
      throw new Error(`Failed to clone ${owner}/${repo}: ${unknownMsg}`);
    }

    await addSafeDirectory(toRepoPath(repoPath));
  }

  /**
   * Auto-detect and load commands from .archon/commands/ (or configured folder)
   */
  private async autoDetectAndLoadCommands(repoPath: string, codebaseId: string): Promise<void> {
    const commandFolders = getCommandFolderSearchPaths();

    for (const folder of commandFolders) {
      try {

View on GitHub (pinned to 0773b97458)

Solutions

  1. Regenerate GITEA_TOKEN in Gitea with repo read scope and update the adapter's environment.
  2. Test the token directly: curl -H "Authorization: token $GITEA_TOKEN" <gitea>/api/v1/user.
  3. Confirm the token belongs to an account with read access to owner/repo on the correct instance.
  4. Check that the token is actually reaching git (credential helper / remote URL embeds the token).

Example fix

// before
clone of https://gitea.example.com/owner/repo.git -> permission_denied (token scopes: read:user)

// after
# regenerate token with "repository" read scope
GITEA_TOKEN=<token with repository:read>
Defensive patterns

Strategy: validation

Validate before calling

const res = await fetch(`${giteaUrl}/api/v1/user`, { headers: { Authorization: `token ${token}` } });
if (res.status === 401) throw new Error('GITEA_TOKEN rejected: regenerate with repository read scope');

Try / catch

try {
  await adapter.handleWebhook(update);
} catch (err) {
  if (String(err).startsWith('Authentication failed for')) {
    alertOperator('GITEA_TOKEN invalid or under-scoped for ' + extractRepo(String(err)));
  }
  throw err;
}

Prevention

When it happens

Trigger: handleWebhook -> ensureRepoReady cloning with a token that is expired, revoked, wrong for the instance, or scoped to a user without read access; token present but sent with a malformed Authorization header by the git credential helper.

Common situations: Gitea token regenerated without updating the adapter's env; token created without any scope; deploying the adapter with a token from a different Gitea instance; LDAP/SSO user disabled so the token is invalidated.

Understand the failure class

Related errors


AI-assisted analysis of coleam00/Archon@0773b97458 (2026-09-01). Data as JSON: /api/errors/36ca0b6a661f0d1d. Report an issue: GitHub.