gastownhall/beads · error

Azure DevOps PAT not configured (set ado.pat or AZURE_DEVOPS

Error message

Azure DevOps PAT not configured (set ado.pat or AZURE_DEVOPS_PAT)

What it means

Tracker.Init validates configuration before making any network calls. It reads the Azure DevOps PAT from config key 'ado.pat' or environment variable AZURE_DEVOPS_PAT; if neither is set (empty string), initialization fails immediately with this fixed message so sync never starts unauthenticated.

Source

Thrown at internal/ado/tracker.go:83

}

// Name returns the lowercase identifier for this tracker.
func (t *Tracker) Name() string { return "ado" }

// DisplayName returns the human-readable name for this tracker.
func (t *Tracker) DisplayName() string { return "Azure DevOps" }

// ConfigPrefix returns the config key prefix for this tracker.
func (t *Tracker) ConfigPrefix() string { return "ado" }

// Init initializes the tracker with configuration from the beads config store.
// No network calls are made during initialization.
func (t *Tracker) Init(ctx context.Context, store storage.Storage) error {
	t.store = store

	pat := t.getConfig(ctx, "ado.pat", "AZURE_DEVOPS_PAT")
	if pat == "" {
		return fmt.Errorf("Azure DevOps PAT not configured (set ado.pat or AZURE_DEVOPS_PAT)")
	}

	t.org = t.getConfig(ctx, "ado.org", "AZURE_DEVOPS_ORG")
	customURL := t.getConfig(ctx, "ado.url", "AZURE_DEVOPS_URL")

	if t.org == "" && customURL == "" {
		return fmt.Errorf("Azure DevOps organization not configured (set ado.org or AZURE_DEVOPS_ORG)")
	}

	// Resolve projects: use pre-set projects (from CLI), or fall back to config.
	if len(t.projects) == 0 {
		pluralVal := t.getConfig(ctx, "ado.projects", "AZURE_DEVOPS_PROJECTS")
		singularVal := t.getConfig(ctx, "ado.project", "AZURE_DEVOPS_PROJECT")
		t.projects = tracker.ResolveProjectIDs(nil, pluralVal, singularVal)
	}
	if len(t.projects) == 0 {
		return fmt.Errorf("Azure DevOps project not configured (set ado.project, ado.projects, or AZURE_DEVOPS_PROJECT)")
	}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Set the environment variable: export AZURE_DEVOPS_PAT=<your-token> in the shell/CI environment running bd.
  2. Or persist it in beads config: bd config set ado.pat <your-token> (or the equivalent config command your setup uses).
  3. In CI, ensure the secret AZURE_DEVOPS_PAT is mapped into the job's environment.
  4. Generate a new PAT in Azure DevOps (User Settings > Personal Access Tokens) with Work Items read/write scope if the old one was revoked.

Example fix

// before: running sync without credentials -> error
$ bd ado sync
// after: configure the PAT first
$ export AZURE_DEVOPS_PAT="xxxxx..."
$ bd ado sync
Defensive patterns

Strategy: validation

Validate before calling

func ensureADOPat() error {
    if os.Getenv("AZURE_DEVOPS_PAT") == "" {
        if _, err := os.Stat(configPathWithAdoPat); err != nil {
            return fmt.Errorf("set AZURE_DEVOPS_PAT or ado.pat before running ADO sync")
        }
    }
    return nil
}

Type guard

func patConfigured(pat string) bool { return pat != "" }

Try / catch

if err := tracker.Init(ctx, store); err != nil {
    if strings.Contains(err.Error(), "PAT not configured") {
        return fmt.Errorf("run: export AZURE_DEVOPS_PAT=<token> (Work Items read/write scope), then retry")
    }
    return err
}

Prevention

When it happens

Trigger: Calling Init (directly or via runADOSync / runGitHubSync / ADO round-trip tests) when both the 'ado.pat' storage config value and the AZURE_DEVOPS_PAT environment variable are unset or empty.

Common situations: Fresh checkout where the PAT was never configured; CI environment missing the AZURE_DEVOPS_PAT secret; PAT stored under a different env var name; running in a shell where the variable wasn't exported; PAT set to empty string after revocation.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/4ac9a841446535a0. Report an issue: GitHub.