Skip to content

feat(config): add environment variable validation#76

Merged
Kavirubc merged 2 commits intosimiligh:mainfrom
mahsumaktas:feat/config-validation
Feb 19, 2026
Merged

feat(config): add environment variable validation#76
Kavirubc merged 2 commits intosimiligh:mainfrom
mahsumaktas:feat/config-validation

Conversation

@mahsumaktas
Copy link
Copy Markdown
Contributor

@mahsumaktas mahsumaktas commented Feb 18, 2026

Summary

Adds startup validation for required config fields so users get clear, actionable error messages instead of cryptic provider failures when environment variables are missing.

Closes #52

Changes

internal/core/config/config.go

  • Added Validate() error method that checks 5 required fields: qdrant.url, qdrant.api_key, qdrant.collection, embedding.api_key, llm.api_key
  • Error messages include the field name AND the expected env var: "config validation failed: qdrant.url is empty (check QDRANT_URL environment variable)"
  • Wired into all load paths: Load(), LoadWithInheritance() (both no-extends and merged paths)

Before / After

Before (missing QDRANT_URL):

Error: dial tcp: lookup : no such host

After:

config validation failed: qdrant.url is empty (check QDRANT_URL environment variable)

Tests

  • TestConfigValidate — 7 cases: all-valid, each missing field, partial config
  • TestLoadValidatesExpandedEnvironmentVariables — end-to-end with real YAML + t.Setenv
  • TestLoadWithInheritanceValidatesMergedConfig — validates merged parent+child config
  • All tests pass: go test ./internal/core/config

Summary by CodeRabbit

  • Bug Fixes

    • Configuration validation now enforces presence of required fields for Qdrant, Embedding, and LLM services, with error messages guiding users to relevant environment variables.
  • Tests

    • Added comprehensive validation tests covering configuration completeness and environment variable expansion scenarios.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 18, 2026

📝 Walkthrough

Walkthrough

A new Validate() method is added to the Config struct to enforce required configuration fields (Qdrant URL/APIKey, Embedding APIKey, LLM APIKey). The validation is called after loading and merging configurations to catch missing environment variables with clear error messages.

Changes

Cohort / File(s) Summary
Config Validation Implementation
internal/core/config/config.go
Adds Validate() method that checks required fields (Qdrant.URL, Qdrant.APIKey, Qdrant.CollectionName, Embedding.APIKey, LLM.APIKey) and returns descriptive errors. Invokes validation after applying defaults in Load() and after merging in LoadWithInheritance().
Config Validation Tests
internal/core/config/config_test.go
Adds three test functions: TestConfigValidate() for table-driven validation scenarios, TestLoadValidatesExpandedEnvironmentVariables() for environment variable expansion failures, and TestLoadWithInheritanceValidatesMergedConfig() for validation on merged inherited configs.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 Through config burrows we now skip,
Each field checked with a careful trip,
No silent empty strings today,
Validation lights the clearer way! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 62.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(config): add environment variable validation' accurately and concisely describes the main change: adding validation for environment variables in the config module.
Linked Issues check ✅ Passed The PR fully implements the requirements from issue #52: adds a Validate() error method to Config struct, checks required fields (qdrant.url, qdrant.api_key, qdrant.collection, embedding.api_key, llm.api_key), provides clear error messages with field names and environment variables, and calls validation in all load paths.
Out of Scope Changes check ✅ Passed All changes are focused on configuration validation: the Validate() method implementation and comprehensive test coverage directly address issue #52 requirements with no unrelated modifications.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Signed-off-by: Mahsum Aktas <mahsum@mahsumaktas.com>
@Kavirubc
Copy link
Copy Markdown
Contributor

Hi @mahsumaktas ,

This issue was already assigned to @Sachindu-Nethmin before you added the PR. Only this one time I will be reviewing and merging this if there are no issues. But after this do not work on issues that are already assigned to others.

It is best if you

  1. Comment on the issue asking to contribute
  2. Wait for assigning the issue to you
  3. Finalize the implementation plan before coding (This is only for larger features which need some input from me and other developers)

Thanks.

Copy link
Copy Markdown
Contributor

@Kavirubc Kavirubc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean implementation of startup validation. Calling Validate() after applyDefaults() in all three load paths is the right order — defaults only touch thresholds and providers, never API keys or URLs, so no risk of false positives.

Exporting Validate() is a nice touch too, keeps it usable independently if needed down the line.

Two minor nits, neither blocking:

  • Currently fail-fast (reports only the first missing field). If onboarding friction becomes an issue, collecting all errors in a single pass would be a small improvement.
  • Any test outside the config package that calls Load() with a partial config will now fail at validation, which is correct behavior but worth keeping in mind as the test suite grows.

Build green, all load paths covered, tests solid. Approving.

@Kavirubc Kavirubc added the e2e label Feb 19, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
internal/core/config/config_test.go (1)

160-256: Well-structured table-driven tests — consider adding a whitespace-only value case.

All 5 required fields and the partial-config scenario are covered. Validate() explicitly calls strings.TrimSpace, but no test case exercises a field value that is non-empty yet all-whitespace (e.g., URL: " "). Adding one case would confirm that strings.TrimSpace behavior is intentional and tested.

♻️ Proposed additional test case
 		{
 			name: "partial config",
 			cfg: Config{
 				Qdrant: QdrantConfig{
 					URL: "https://example.qdrant.io:6334",
 				},
 			},
 			wantErr: "config validation failed: qdrant.api_key is empty (check QDRANT_API_KEY environment variable)",
 		},
+		{
+			name: "whitespace-only qdrant url",
+			cfg: func() Config {
+				cfg := baseConfig
+				cfg.Qdrant.URL = "   "
+				return cfg
+			}(),
+			wantErr: "config validation failed: qdrant.url is empty (check QDRANT_URL environment variable)",
+		},
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/core/config/config_test.go` around lines 160 - 256, Add a
whitespace-only value test to TestConfigValidate to exercise strings.TrimSpace
behavior: create a new test case in the tests slice that copies baseConfig, sets
a field to a whitespace-only string (e.g., cfg.Qdrant.URL = "   " or
cfg.Embedding.APIKey = "   "), call cfg.Validate() and assert it returns the
same error string as the empty-value case (e.g., "config validation failed:
qdrant.url is empty (check QDRANT_URL environment variable)"); this verifies
Validate() treats all-whitespace as empty.
internal/core/config/config.go (1)

190-215: Consider collecting all validation errors before returning.

The current fail-fast approach (returning on the first empty field) requires a fix-and-restart cycle for each missing field. When multiple required fields are absent on a first deployment, users face sequential error discovery. Aggregating all failures into a single error would improve the startup experience.

♻️ Proposed refactor to collect all missing fields
 func (c *Config) Validate() error {
 	requiredFields := []struct {
 		name   string
 		envVar string
 		value  string
 	}{
 		{name: "qdrant.url", envVar: "QDRANT_URL", value: c.Qdrant.URL},
 		{name: "qdrant.api_key", envVar: "QDRANT_API_KEY", value: c.Qdrant.APIKey},
 		{name: "qdrant.collection", envVar: "QDRANT_COLLECTION", value: c.Qdrant.Collection},
 		{name: "embedding.api_key", envVar: "EMBEDDING_API_KEY", value: c.Embedding.APIKey},
 		{name: "llm.api_key", envVar: "LLM_API_KEY", value: c.LLM.APIKey},
 	}

+	var missing []string
 	for _, field := range requiredFields {
 		if strings.TrimSpace(field.value) == "" {
-			return fmt.Errorf(
-				"config validation failed: %s is empty (check %s environment variable)",
-				field.name,
-				field.envVar,
-			)
+			missing = append(missing, fmt.Sprintf("%s (check %s environment variable)", field.name, field.envVar))
 		}
 	}

+	if len(missing) > 0 {
+		return fmt.Errorf("config validation failed: missing required fields: %s", strings.Join(missing, "; "))
+	}
+
 	return nil
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/core/config/config.go` around lines 190 - 215, Change
Config.Validate to collect all missing required fields instead of returning on
the first error: iterate the requiredFields slice (the local variable in
Validate that contains entries like {name: "qdrant.url", envVar: "QDRANT_URL",
value: c.Qdrant.URL}), append a descriptive message for each empty value (use
strings.TrimSpace(field.value) == "") to a list, and after the loop return a
single aggregated error that joins all messages (or nil if none). Keep the same
message format per field ("<name> is empty (check <envVar> environment
variable)") and ensure the function still returns nil when there are no missing
fields.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@internal/core/config/config_test.go`:
- Around line 160-256: Add a whitespace-only value test to TestConfigValidate to
exercise strings.TrimSpace behavior: create a new test case in the tests slice
that copies baseConfig, sets a field to a whitespace-only string (e.g.,
cfg.Qdrant.URL = "   " or cfg.Embedding.APIKey = "   "), call cfg.Validate() and
assert it returns the same error string as the empty-value case (e.g., "config
validation failed: qdrant.url is empty (check QDRANT_URL environment
variable)"); this verifies Validate() treats all-whitespace as empty.

In `@internal/core/config/config.go`:
- Around line 190-215: Change Config.Validate to collect all missing required
fields instead of returning on the first error: iterate the requiredFields slice
(the local variable in Validate that contains entries like {name: "qdrant.url",
envVar: "QDRANT_URL", value: c.Qdrant.URL}), append a descriptive message for
each empty value (use strings.TrimSpace(field.value) == "") to a list, and after
the loop return a single aggregated error that joins all messages (or nil if
none). Keep the same message format per field ("<name> is empty (check <envVar>
environment variable)") and ensure the function still returns nil when there are
no missing fields.

@gh-simili-bot
Copy link
Copy Markdown
Contributor

🧪 E2E Test

Bot responded: yes

Test repo → gh-simili-bot/simili-e2e-22170026950
Run → logs

Auto-generated by E2E pipeline

@Kavirubc Kavirubc merged commit 453f087 into similigh:main Feb 19, 2026
7 checks passed
Sachindu-Nethmin pushed a commit to Sachindu-Nethmin/simili-bot that referenced this pull request Feb 19, 2026
…ligh#76)

Signed-off-by: Mahsum Aktas <mahsum@mahsumaktas.com>
Co-authored-by: Kaviru Hapuarachchi <41495525+Kavirubc@users.noreply.github.com>
Signed-off-by: Sachindu-Nethmin <sachindunethminweerasinghe@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[UX]: Add Configuration Validation for Environment Variables

3 participants