{"record":{"id":"9dd5cb0fdf827ad5","repo":"gastownhall/beads","slug":"notion-token-not-configured","errorCode":null,"errorMessage":"Notion token not configured","messagePattern":"Notion token not configured","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/notion/client.go","lineNumber":249,"sourceCode":"\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"retrieve child data source %s: %w\", resolvedID, err)\n\t\t}\n\t\treturn &ResolvedDataSource{\n\t\t\tInputID:      identifier,\n\t\t\tDataSourceID: resolvedID,\n\t\t\tDataSource:   resolvedDS,\n\t\t\tDatabase:     db,\n\t\t\tViewURL:      strings.TrimSpace(ref),\n\t\t}, nil\n\t}\n}\n\nfunc (c *Client) doRequest(ctx context.Context, method, path string, requestBody interface{}) ([]byte, error) {\n\tif c == nil {\n\t\treturn nil, fmt.Errorf(\"notion client is nil\")\n\t}\n\tif strings.TrimSpace(c.Token) == \"\" {\n\t\treturn nil, fmt.Errorf(\"Notion token not configured\")\n\t}\n\thttpClient := c.HTTPClient\n\tif httpClient == nil {\n\t\thttpClient = &http.Client{Timeout: DefaultTimeout}\n\t}\n\n\tvar bodyReader io.Reader\n\tif requestBody != nil {\n\t\tpayload, err := json.Marshal(requestBody)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"marshal request body: %w\", err)\n\t\t}\n\t\tbodyReader = bytes.NewReader(payload)\n\t}\n\n\trequestURL := path\n\tif !strings.HasPrefix(requestURL, \"http://\") && !strings.HasPrefix(requestURL, \"https://\") {\n\t\trequestURL = strings.TrimSuffix(c.BaseURL, \"/\") + path","sourceCodeStart":231,"sourceCodeEnd":267,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/notion/client.go#L231-L267","documentation":"The Client exists but its Token field is empty or whitespace-only, so doRequest aborts before building the HTTP request. Notion's API requires a Bearer integration token; the library fails fast with a clear message instead of receiving a 401 from the server. This is purely a local configuration check (strings.TrimSpace(c.Token) == \"\").","triggerScenarios":"Client constructed with an empty token: notion.NewClient(\"\") or NewClient(os.Getenv(\"NOTION_TOKEN\")) when NOTION_TOKEN is unset/empty; a config struct unmarshaled without the token key; token set only to spaces via env or config file.","commonSituations":"Missing NOTION_TOKEN env var in CI or .env not loaded; YAML/JSON config missing the notion.token key so it unmarshals as \"\"; Docker container deployed without the secret injected; renaming the env var without updating the loader.","solutions":["Export the token before running: export NOTION_TOKEN=\"ntn_...\" (or set it in .env / deployment secrets).","Pass the token explicitly to the client constructor and log a startup error if it is empty.","Validate configuration at startup: if strings.TrimSpace(cfg.NotionToken) == \"\" { return errors.New(\"NOTION_TOKEN is required\") }.","Verify the secret is actually mounted in the runtime environment (docker inspect / kubectl describe pod), not just present locally."],"exampleFix":"// before\nclient := notion.NewClient(os.Getenv(\"NOTION_TOKEN\")) // silently empty\n\n// after\ntoken := os.Getenv(\"NOTION_TOKEN\")\nif strings.TrimSpace(token) == \"\" {\n    return fmt.Errorf(\"NOTION_TOKEN must be set\")\n}\nclient := notion.NewClient(token)","handlingStrategy":"validation","validationCode":"token := os.Getenv(\"NOTION_TOKEN\")\nif strings.TrimSpace(token) == \"\" {\n    return fmt.Errorf(\"NOTION_TOKEN is required\")\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"Notion token not configured\") {\n    log.Fatal(\"set NOTION_TOKEN in your environment\")\n}","preventionTips":["Validate required env/config at process startup with fail-fast checks.","Use a config-loading library that reports missing keys instead of defaulting to empty strings.","Keep secrets out of code; document required env vars in README/CI setup."],"tags":["notion","authentication","missing-credential","configuration"],"backgroundTag":"missing-env-var","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}