gastownhall/beads · error

Jira API token not configured (set jira.api_token or JIRA_AP

Error message

Jira API token not configured (set jira.api_token or JIRA_API_TOKEN)

What it means

Tracker.Init requires an API token to authenticate the Jira client. It reads 'jira.api_token' with JIRA_API_TOKEN as env fallback; if the lookup errors or the token is empty, Init aborts with this message. A username is read alongside it (optional for some auth modes) but the token itself is mandatory — the client cannot sign requests without it.

Source

Thrown at internal/jira/tracker.go:83

	if err != nil || jiraURL == "" {
		return fmt.Errorf("Jira URL not configured (set jira.url or JIRA_URL)")
	}
	t.jiraURL = jiraURL

	// Resolve project keys: use pre-set keys (from CLI), or fall back to config.
	if len(t.projectKeys) == 0 {
		pluralVal, _ := t.getConfig(ctx, "jira.projects", "JIRA_PROJECTS")
		singularVal, _ := t.getConfig(ctx, "jira.project", "JIRA_PROJECT")
		t.projectKeys = tracker.ResolveProjectIDs(nil, pluralVal, singularVal)
	}
	if len(t.projectKeys) == 0 {
		return fmt.Errorf("Jira project not configured (set jira.project, jira.projects, or JIRA_PROJECT)")
	}

	username, _ := t.getConfig(ctx, "jira.username", "JIRA_USERNAME")
	apiToken, err := t.getConfig(ctx, "jira.api_token", "JIRA_API_TOKEN")
	if err != nil || apiToken == "" {
		return fmt.Errorf("Jira API token not configured (set jira.api_token or JIRA_API_TOKEN)")
	}

	t.client = NewClient(jiraURL, username, apiToken)

	apiVersion, _ := t.getConfig(ctx, "jira.api_version", "JIRA_API_VERSION")
	if apiVersion == "" {
		apiVersion = "3"
	}
	t.apiVersion = apiVersion
	t.client.APIVersion = apiVersion

	// Load optional custom status map from all jira.status_map.* config keys.
	// Using GetAllConfig supports arbitrary (including custom) beads status names.
	if allConfig, err := t.store.GetAllConfig(ctx); err == nil {
		const statusPrefix = "jira.status_map."
		statusMap := make(map[string]string)
		for key, val := range allConfig {
			if strings.HasPrefix(key, statusPrefix) && val != "" {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Generate an API token at id.atlassian.com (Cloud) or set a PAT (Server/DC) and export JIRA_API_TOKEN with it.
  2. Or set jira.api_token in the config store.
  3. Verify the secret is actually injected into the runtime environment (CI secrets, k8s secret mounts, .env loading).
  4. Confirm the variable name matches JIRA_API_TOKEN exactly.
  5. Pair it with the correct username/email — a token without its matching account will fail later with 401 even when init passes.

Example fix

// before: token not in environment
_ = tracker.Init(ctx, store) // → error
// after
os.Setenv("JIRA_API_TOKEN", os.Getenv("ATLASSIAN_API_TOKEN"))
os.Setenv("JIRA_USERNAME", "dev@yourorg.com")
_ = tracker.Init(ctx, store)
Defensive patterns

Strategy: validation

Validate before calling

func hasTokenConfig() bool {
    return os.Getenv("JIRA_API_TOKEN") != ""
}
// call before Init; also verify JIRA_USERNAME is set for Cloud basic auth

Try / catch

if err := tracker.Init(ctx, store); err != nil {
    if strings.Contains(err.Error(), "API token not configured") {
        return fmt.Errorf("export JIRA_API_TOKEN (generate at id.atlassian.com)")
    }
    return err
}

Prevention

When it happens

Trigger: Init reaches the credential check (URL and project already valid) and jira.api_token/JIRA_API_TOKEN is missing, empty, or getConfig errors.

Common situations: Token stored in a secret manager not injected into the environment; token rotated/expired and removed; running locally where .env is not loaded; mismatched variable name (ATLASSIAN_API_TOKEN, JIRA_TOKEN); username set but token forgotten.

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/7f730dd7c493f61f. Report an issue: GitHub.