semaphoreui/semaphore · error

missing secret

Error message

missing secret

What it means

Environment.Validate on an EnvironmentSecret (EnvironmentVar/EnvironmentPassword type) requires the Secret field to be non-empty. Secret-typed environment entries must reference a stored secret value; an empty Secret means the entry carries no credential and would silently resolve to nothing at job runtime, so validation rejects it up front.

Solutions

  1. Provide a non-empty "secret" value in the environment entry's JSON payload
  2. If the entry holds a plain value, change its type to EnvironmentSecretVar (or EnvironmentSecretEnv) so the secret check is skipped
  3. Templating tools: fail fast on empty variables instead of emitting empty strings into the env JSON

Example fix

// before
{"HOME_VAR": {"type": "password", "secret": ""}}
// after
{"HOME_VAR": {"type": "password", "secret": "vault-stored-password"}}
Defensive patterns

Strategy: validation

Validate before calling

if entry.Type != "var" && entry.Type != "env" && strings.TrimSpace(entry.Secret) == "" {
	return errors.New("secret entry requires a non-empty secret value")
}

Type guard

func secretEntryIsValid(s db.EnvironmentSecret) bool {
	if s.Type == db.EnvironmentSecretVar || s.Type == db.EnvironmentSecretEnv { return true }
	return s.Secret != ""
}

Try / catch

if err := env.Validate(); err != nil {
	if strings.Contains(err.Error(), "missing secret") {
		return fmt.Errorf("environment rejected: %w", err)
	}
	return err
}

Prevention

When it happens

Trigger: Creating or updating an environment via the API (POST/PUT /api/environments) whose JSON env-vars payload contains an entry with type EnvironmentPassword (or a non-var/env type) and an empty/missing "secret" field, validated by Validate.

Common situations: Ansible/Terraform automation templating environment JSON where the secret variable is undefined and renders as an empty string; copying an environment definition between projects and dropping the secret value; users picking the wrong secret type when entering environment variables in the UI.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of semaphoreui/semaphore@1774ccb71a (2026-09-07). Data as JSON: /api/errors/0d9ebfcdaaa5bef8. Report an issue: GitHub.

Appendix: source

Thrown at db/Environment.go:75

	SecretStorageID        *int    `db:"secret_storage_id" json:"secret_storage_id,omitempty" backup:"-"`
	SecretStorageKeyPrefix *string `db:"secret_storage_key_prefix" json:"secret_storage_key_prefix,omitempty"`

	// Sync fields are transfer-only; persisted in project__secret_sync.
	SyncEnabled      bool             `db:"-" json:"sync_enabled"`
	SyncInterval     int              `db:"-" json:"sync_interval"`
	LastSyncedAt     *time.Time       `db:"-" json:"last_synced_at,omitempty"`
	LastSyncFailedAt *time.Time       `db:"-" json:"last_sync_failed_at,omitempty"`
	SyncPaths        []SecretSyncPath `db:"-" json:"sync_paths"`
}

func (s *EnvironmentSecret) Validate() error {

	if s.Type == EnvironmentSecretVar || s.Type == EnvironmentSecretEnv {
		return nil
	}

	if s.Secret == "" {
		return errors.New("missing secret")
	}

	return errors.New("invalid environment secret type")
}

func validateJSON(s string, mustValuesBeScalar bool) error {
	if s == "" {
		return nil
	}

	var data map[string]any
	err := json.Unmarshal([]byte(s), &data)
	if err != nil {
		return errors.New("must be valid JSON")
	}

	for k, v := range data {
		if k == "" {

View on GitHub (pinned to 1774ccb71a)