{"record":{"id":"308c610431f10500","repo":"Tencent/WeKnora","slug":"w-missing-api-key","errorCode":null,"errorMessage":"%w: missing api_key","messagePattern":"%w: missing api_key","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/datasource/connector/notion/types.go","lineNumber":41,"sourceCode":"const NotionAPIVersion = \"2026-03-11\"\n\n// DefaultBaseURL is the Notion API base URL.\nconst DefaultBaseURL = \"https://api.notion.com\"\n\n// Config holds Notion-specific configuration for the data source connector.\ntype Config struct {\n\tAPIKey string `json:\"api_key\"` // Internal Integration Token\n}\n\n// parseNotionConfig extracts and validates Notion config from DataSourceConfig.\nfunc parseNotionConfig(config *types.DataSourceConfig) (*Config, error) {\n\tif config == nil {\n\t\treturn nil, datasource.ErrInvalidConfig\n\t}\n\n\ttokenVal, ok := config.Credentials[\"api_key\"]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"%w: missing api_key\", datasource.ErrInvalidCredentials)\n\t}\n\ttoken, ok := tokenVal.(string)\n\tif !ok || token == \"\" {\n\t\treturn nil, fmt.Errorf(\"%w: api_key must be a non-empty string\", datasource.ErrInvalidCredentials)\n\t}\n\n\treturn &Config{APIKey: token}, nil\n}\n\n// --- API response types ---\n\n// notionPage represents a Notion page or database object.\ntype notionPage struct {\n\tID             string       `json:\"id\"`\n\tObject         string       `json:\"object\"` // \"page\" | \"database\" | \"data_source\" (2025-09-03+)\n\tParent         notionParent `json:\"parent\"`\n\tURL            string       `json:\"url\"`\n\tLastEditedTime time.Time    `json:\"last_edited_time\"`","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/datasource/connector/notion/types.go#L23-L59","documentation":"parseNotionConfig validates the datasource config's credentials. The credential map must contain an \"api_key\" entry; if the key is absent the config is rejected with ErrInvalidCredentials wrapped with \"missing api_key\". Callers can match with errors.Is to detect bad credentials.","triggerScenarios":"Any of Validate, ListResources, FetchAll, FetchIncremental receives a config whose Credentials map has no \"api_key\" key.","commonSituations":"Environment variable supplying the Notion token is unset so the credential map omits the key; config file lacks the api_key field; UI saved credentials without the field.","solutions":["Set the \"api_key\" credential to a valid Notion integration token (secret_...)","Create an integration at notion.so/my-integrations if you have no token","Verify the env var or config source feeding Credentials is not empty","Call Validate before Fetch to catch this early"],"exampleFix":"// before\ncreds := map[string]interface{}{}\n// after\ncreds := map[string]interface{}{\n    \"api_key\": os.Getenv(\"NOTION_API_KEY\"),\n}","handlingStrategy":"validation","validationCode":"creds := config.Credentials; if creds == nil || creds[\"api_key\"] == nil { return errors.New(\"api_key credential required\") }","typeGuard":"func hasAPIKey(cfg *datasource.Config) bool {\n    if cfg == nil || cfg.Credentials == nil { return false }\n    v, ok := cfg.Credentials[\"api_key\"]\n    return ok && v != nil\n}","tryCatchPattern":"if err := connector.Validate(ctx, cfg); err != nil {\n    if errors.Is(err, datasource.ErrInvalidCredentials) {\n        return errors.New(\"configure NOTION_API_KEY / api_key credential\")\n    }\n    return err\n}","preventionTips":["Store the Notion integration token in a secret manager and inject it into Credentials","Check secret injection at startup (fail fast if empty)","Document the exact credential key name: \"api_key\""],"tags":["notion","credentials","configuration","validation"],"backgroundTag":"missing-env-var","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}