{"record":{"id":"75c8a651a08a2d07","repo":"Tencent/WeKnora","slug":"errinvalidconfig","errorCode":"ErrInvalidConfig","errorMessage":"%w: config is nil","messagePattern":"%w: config is nil","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/datasource/connector/rss/types.go","lineNumber":57,"sourceCode":"// Config holds RSS-specific configuration.\n//\n// FeedURLs are stored in DataSourceConfig.Settings (non-secret, editable in\n// the UI without replacing credentials). AuthHeaders live in Credentials\n// because they may carry secrets that must be encrypted at rest. Credentials\n// may still carry feed_urls for backward compatibility with older rows.\ntype Config struct {\n\t// FeedURLs is a newline- or comma-separated list of feed URLs.\n\tFeedURLs string `json:\"feed_urls\"`\n\n\t// AuthHeaders is an optional newline-separated list of custom request\n\t// headers in \"Name: Value\" form, applied only to feed fetches.\n\tAuthHeaders string `json:\"auth_headers,omitempty\"`\n}\n\n// parseConfig extracts and validates RSS configuration.\nfunc parseConfig(config *types.DataSourceConfig) (*Config, error) {\n\tif config == nil {\n\t\treturn nil, fmt.Errorf(\"%w: config is nil\", datasource.ErrInvalidConfig)\n\t}\n\tcredBytes, err := json.Marshal(config.Credentials)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"marshal credentials: %w\", err)\n\t}\n\tvar cfg Config\n\tif err := json.Unmarshal(credBytes, &cfg); err != nil {\n\t\treturn nil, fmt.Errorf(\"parse rss credentials: %w\", err)\n\t}\n\tif urls := feedURLsFromSettings(config.Settings); urls != \"\" {\n\t\tcfg.FeedURLs = urls\n\t}\n\tif len(cfg.feedURLList()) == 0 {\n\t\treturn nil, fmt.Errorf(\"%w: feed_urls is required\", datasource.ErrInvalidCredentials)\n\t}\n\treturn &cfg, nil\n}\n","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/datasource/connector/rss/types.go#L39-L75","documentation":"parseConfig in the RSS connector wraps datasource.ErrInvalidConfig when it is handed a nil *types.DataSourceConfig. The wrapper refuses to do any work because there is no configuration object at all to extract feed URLs or credentials from. Callers (Validate, ListResources, walk) should never pass nil; this is a defensive guard.","triggerScenarios":"Any call to Validate, ListResources, or walk on the RSS connector where the *types.DataSourceConfig argument is nil, e.g. an upstream service built the config object conditionally and skipped it, or a test harness invoked the connector without a config.","commonSituations":"A datasource record was deleted or not yet created but the UI still triggered a validation; a migration or restore produced sources with an empty/missing config blob that decoded to nil; unit tests calling parseConfig directly without constructing a DataSourceConfig.","solutions":["Ensure the caller constructs and passes a non-nil *types.DataSourceConfig before invoking the connector.","Check where the DataSourceConfig is loaded (DB/HTTP) and treat a missing config as an earlier, user-facing validation failure instead of reaching the connector.","If seen in tests, build a minimal config: &types.DataSourceConfig{Credentials: map[string]interface{}{\"feed_urls\": \"https://example.com/feed\"}}.","Add an upstream nil-check/guard so the connector is never invoked without a config."],"exampleFix":"// before\nconn.Validate(ctx, nil)\n// after\ncfg := &types.DataSourceConfig{Credentials: map[string]interface{}{\"feed_urls\": \"https://example.com/rss\"}}\nif cfg == nil { return errors.New(\"missing datasource config\") }\nconn.Validate(ctx, cfg)","handlingStrategy":"validation","validationCode":"if config == nil {\n    return fmt.Errorf(\"datasource config is missing; cannot validate RSS source\")\n}\nif len(config.Credentials) == 0 && len(config.Settings) == 0 {\n    return fmt.Errorf(\"datasource config has no credentials or settings\")\n}","typeGuard":"func hasConfig(c *types.DataSourceConfig) bool { return c != nil }","tryCatchPattern":"cfg, err := parseConfig(config)\nif errors.Is(err, datasource.ErrInvalidConfig) {\n    // surface as user-facing \"source not configured\"\n    return err\n}","preventionTips":["Always construct DataSourceConfig via a factory/validator before invoking connectors.","Reject unconfigured sources at the service layer before reaching connector code.","Add unit tests covering nil-config paths for every connector."],"tags":["go","config","rss","nil-config"],"backgroundTag":"nil-config","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}