{"record":{"id":"10c776781c72a8a5","repo":"Tencent/WeKnora","slug":"engine-id-is-required-for-google-provider-10c776","errorCode":null,"errorMessage":"engine ID is required for Google provider","messagePattern":"engine ID is required for Google provider","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/infrastructure/web_search/google.go","lineNumber":30,"sourceCode":"\t\"github.com/Tencent/WeKnora/internal/types\"\n\t\"github.com/Tencent/WeKnora/internal/types/interfaces\"\n)\n\n// GoogleProvider implements web search using Google Custom Search Engine API\ntype GoogleProvider struct {\n\tsrv      *customsearch.Service\n\tapiKey   string\n\tengineID string\n}\n\n// NewGoogleProvider creates a new Google provider from parameters (no environment variables).\n// The API endpoint is the official Google Custom Search endpoint — not tenant-configurable.\nfunc NewGoogleProvider(params types.WebSearchProviderParameters) (interfaces.WebSearchProvider, error) {\n\tif params.APIKey == \"\" {\n\t\treturn nil, fmt.Errorf(\"API key is required for Google provider\")\n\t}\n\tif params.EngineID == \"\" {\n\t\treturn nil, fmt.Errorf(\"engine ID is required for Google provider\")\n\t}\n\n\thttpClient, err := NewSearchHTTPClient(30*time.Second, params.ProxyURL)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tclientOpts := []option.ClientOption{\n\t\toption.WithAPIKey(params.APIKey),\n\t\toption.WithHTTPClient(httpClient),\n\t}\n\tsrv, err := customsearch.NewService(context.Background(), clientOpts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &GoogleProvider{\n\t\tsrv:      srv,\n\t\tapiKey:   params.APIKey,\n\t\tengineID: params.EngineID,","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/infrastructure/web_search/google.go#L12-L48","documentation":"NewGoogleProvider requires a non-empty EngineID (the Programmable Search/Custom Search Engine ID, cx) and returns this error when it is missing. Like the API key, the engine ID comes only from parameters — there is no environment fallback.","triggerScenarios":"Calling NewGoogleProvider with params.APIKey set but params.EngineID == \"\".","commonSituations":"Developer set the API key but forgot the Programmable Search Engine ID; config schema has no field for engine ID; created an API key but never created/configured the search engine in Google's control panel.","solutions":["Set params.EngineID to the cx value from your Programmable Search Engine settings.","Create a Programmable Search Engine at programmablesearchengine.google.com if none exists and copy its ID.","Ensure the config loader maps the engine ID field into WebSearchProviderParameters."],"exampleFix":"// before\nprovider, err := NewGoogleProvider(types.WebSearchProviderParameters{APIKey: apiKey})\n// after\nprovider, err := NewGoogleProvider(types.WebSearchProviderParameters{APIKey: apiKey, EngineID: cfg.GoogleEngineID})","handlingStrategy":"validation","validationCode":"if params.EngineID == \"\" {\n    return errors.New(\"google search provider requires EngineID (cx) — check config\")\n}\nprovider, err := NewGoogleProvider(params)","typeGuard":null,"tryCatchPattern":"provider, err := NewGoogleProvider(params)\nif err != nil {\n    return nil, fmt.Errorf(\"init google search provider: %w\", err)\n}","preventionTips":["Store the Programmable Search Engine cx value alongside the API key in config","Smoke-test provider construction in CI with representative config","Fail fast at config-load time when engine ID is absent","Document how to obtain the engine ID from programmablesearchengine.google.com"],"tags":["configuration","google","web-search","missing-config"],"backgroundTag":"missing-config-value","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}