semaphoreui/semaphore · error

must be valid JSON

Error message

must be valid JSON

What it means

validateJSON parses an environment's JSON variable payload into map[string]any and returns this error when json.Unmarshal fails, meaning the stored environment JSON is not a syntactically valid JSON object. Environments store their variables as a JSON document, so any string that does not parse as an object is rejected by Validate.

Solutions

  1. Run the payload through a JSON linter or jq to fix syntax errors before sending it
  2. Ensure the payload is a JSON object ({...}), not an array or scalar
  3. Build the payload with a JSON encoder (jq, json.Marshal) instead of string concatenation

Example fix

// before
payload := "{VAR1: 'value1',}" // invalid JSON
// after
payload, _ := json.Marshal(map[string]any{"VAR1": "value1"})
Defensive patterns

Strategy: validation

Validate before calling

var probe map[string]any
if err := json.Unmarshal([]byte(payload), &probe); err != nil {
	return fmt.Errorf("environment payload is not valid JSON: %w", err)
}

Type guard

func isJSONObject(s string) bool {
	var m map[string]any
	return json.Unmarshal([]byte(s), &m) == nil
}

Try / catch

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

Prevention

When it happens

Trigger: Creating/updating an environment where the "json" field contains malformed JSON (trailing commas, unquoted keys, single quotes, truncated output from templating) or a valid JSON value that is not an object (array, string, number).

Common situations: Shell heredocs or jq -c output interpolated with unescaped quotes into the payload; CI scripts concatenating JSON strings manually; pasting YAML instead of JSON into an environment editor.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


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

Appendix: source

Thrown at db/Environment.go:89

		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 == "" {
			return errors.New("key can not be empty")
		}

		if mustValuesBeScalar {
			switch v.(type) {
			case []any, map[string]any:
				return errors.New("values must be scalar")
			}
		}
	}

	return nil
}

View on GitHub (pinned to 1774ccb71a)