Tencent/WeKnora · error
%w: api_key must be a non-empty string
Error message
%w: api_key must be a non-empty string
What it means
parseNotionConfig requires the "api_key" credential to be a non-empty string. If the value exists but is not a string, or is the empty string, the config is rejected with ErrInvalidCredentials wrapped with "api_key must be a non-empty string". This catches mistyped config values (e.g. numbers, nil) and blank tokens.
Source
Thrown at internal/datasource/connector/notion/types.go:45
// Config holds Notion-specific configuration for the data source connector.
type Config struct {
APIKey string `json:"api_key"` // Internal Integration Token
}
// parseNotionConfig extracts and validates Notion config from DataSourceConfig.
func parseNotionConfig(config *types.DataSourceConfig) (*Config, error) {
if config == nil {
return nil, datasource.ErrInvalidConfig
}
tokenVal, ok := config.Credentials["api_key"]
if !ok {
return nil, fmt.Errorf("%w: missing api_key", datasource.ErrInvalidCredentials)
}
token, ok := tokenVal.(string)
if !ok || token == "" {
return nil, fmt.Errorf("%w: api_key must be a non-empty string", datasource.ErrInvalidCredentials)
}
return &Config{APIKey: token}, nil
}
// --- API response types ---
// notionPage represents a Notion page or database object.
type notionPage struct {
ID string `json:"id"`
Object string `json:"object"` // "page" | "database" | "data_source" (2025-09-03+)
Parent notionParent `json:"parent"`
URL string `json:"url"`
LastEditedTime time.Time `json:"last_edited_time"`
InTrash bool `json:"in_trash"`
// Title is extracted from properties after unmarshaling; not directly from JSON.
Title string `json:"-"`
// RawTitle holds the top-level title array (used by database objects).View on GitHub (pinned to 988cbb0330)
Solutions
- Set api_key to the full integration token string (starts with secret_)
- Check the env var actually has a value: echo "$NOTION_API_KEY"
- Fix config file syntax so api_key gets a real string value
- Run Validate first to fail fast with this message
Example fix
// before
token := os.Getenv("NOTION_API_KEY") // may be ""
// after
token := os.Getenv("NOTION_API_KEY")
if token == "" {
log.Fatal("NOTION_API_KEY must be set")
} Defensive patterns
Strategy: type-guard
Validate before calling
token, ok := config.Credentials["api_key"].(string); if !ok || token == "" { return errors.New("api_key must be a non-empty string") } Type guard
func validAPIKey(cfg *datasource.Config) bool {
if cfg == nil || cfg.Credentials == nil { return false }
s, ok := cfg.Credentials["api_key"].(string)
return ok && strings.TrimSpace(s) != ""
} Try / catch
if err := connector.Validate(ctx, cfg); err != nil {
if errors.Is(err, datasource.ErrInvalidCredentials) && strings.Contains(err.Error(), "non-empty string") {
return errors.New("api_key is set but empty or wrong type")
}
return err
} Prevention
- Type-assert credentials before passing them to the connector
- Trim whitespace; treat blank env vars as unset
- Avoid YAML/JSON null or numeric values for api_key
When it happens
Trigger: config.Credentials["api_key"] holds a non-string (e.g. nil from a YAML null, a number) or an empty string, passed to Validate/ListResources/FetchAll/FetchIncremental.
Common situations: Env var set to empty string (exported but blank), secret manager returning nil, config YAML with `api_key:` (empty value), quoting errors in config files.
Related errors
- %w: missing api_key
- invalid sandbox type
- timeout cannot be negative
- memory limit cannot be negative
- CPU limit cannot be negative
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/259a6fea86e753ae.
Report an issue: GitHub.