{"record":{"id":"4ac9a841446535a0","repo":"gastownhall/beads","slug":"azure-devops-pat-not-configured-set-ado-pat-or-az","errorCode":null,"errorMessage":"Azure DevOps PAT not configured (set ado.pat or AZURE_DEVOPS_PAT)","messagePattern":"Azure DevOps PAT not configured \\(set ado\\.pat or AZURE_DEVOPS_PAT\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/ado/tracker.go","lineNumber":83,"sourceCode":"}\n\n// Name returns the lowercase identifier for this tracker.\nfunc (t *Tracker) Name() string { return \"ado\" }\n\n// DisplayName returns the human-readable name for this tracker.\nfunc (t *Tracker) DisplayName() string { return \"Azure DevOps\" }\n\n// ConfigPrefix returns the config key prefix for this tracker.\nfunc (t *Tracker) ConfigPrefix() string { return \"ado\" }\n\n// Init initializes the tracker with configuration from the beads config store.\n// No network calls are made during initialization.\nfunc (t *Tracker) Init(ctx context.Context, store storage.Storage) error {\n\tt.store = store\n\n\tpat := t.getConfig(ctx, \"ado.pat\", \"AZURE_DEVOPS_PAT\")\n\tif pat == \"\" {\n\t\treturn fmt.Errorf(\"Azure DevOps PAT not configured (set ado.pat or AZURE_DEVOPS_PAT)\")\n\t}\n\n\tt.org = t.getConfig(ctx, \"ado.org\", \"AZURE_DEVOPS_ORG\")\n\tcustomURL := t.getConfig(ctx, \"ado.url\", \"AZURE_DEVOPS_URL\")\n\n\tif t.org == \"\" && customURL == \"\" {\n\t\treturn fmt.Errorf(\"Azure DevOps organization not configured (set ado.org or AZURE_DEVOPS_ORG)\")\n\t}\n\n\t// Resolve projects: use pre-set projects (from CLI), or fall back to config.\n\tif len(t.projects) == 0 {\n\t\tpluralVal := t.getConfig(ctx, \"ado.projects\", \"AZURE_DEVOPS_PROJECTS\")\n\t\tsingularVal := t.getConfig(ctx, \"ado.project\", \"AZURE_DEVOPS_PROJECT\")\n\t\tt.projects = tracker.ResolveProjectIDs(nil, pluralVal, singularVal)\n\t}\n\tif len(t.projects) == 0 {\n\t\treturn fmt.Errorf(\"Azure DevOps project not configured (set ado.project, ado.projects, or AZURE_DEVOPS_PROJECT)\")\n\t}","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/ado/tracker.go#L65-L101","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Set the environment variable: export AZURE_DEVOPS_PAT=<your-token> in the shell/CI environment running bd.","Or persist it in beads config: bd config set ado.pat <your-token> (or the equivalent config command your setup uses).","In CI, ensure the secret AZURE_DEVOPS_PAT is mapped into the job's environment.","Generate a new PAT in Azure DevOps (User Settings > Personal Access Tokens) with Work Items read/write scope if the old one was revoked."],"exampleFix":"// before: running sync without credentials -> error\n$ bd ado sync\n// after: configure the PAT first\n$ export AZURE_DEVOPS_PAT=\"xxxxx...\"\n$ bd ado sync","handlingStrategy":"validation","validationCode":"func ensureADOPat() error {\n    if os.Getenv(\"AZURE_DEVOPS_PAT\") == \"\" {\n        if _, err := os.Stat(configPathWithAdoPat); err != nil {\n            return fmt.Errorf(\"set AZURE_DEVOPS_PAT or ado.pat before running ADO sync\")\n        }\n    }\n    return nil\n}","typeGuard":"func patConfigured(pat string) bool { return pat != \"\" }","tryCatchPattern":"if err := tracker.Init(ctx, store); err != nil {\n    if strings.Contains(err.Error(), \"PAT not configured\") {\n        return fmt.Errorf(\"run: export AZURE_DEVOPS_PAT=<token> (Work Items read/write scope), then retry\")\n    }\n    return err\n}","preventionTips":["Export AZURE_DEVOPS_PAT in shell profiles and CI job environments (map the secret).","Store the PAT persistently via the ado.pat config key for non-interactive runs.","Check Init errors immediately at startup before any long-running sync.","Document PAT setup in onboarding docs so fresh environments are configured first."],"tags":["configuration","azure-devops","authentication","env-var"],"backgroundTag":"missing-env-var","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}