gotify/server · error

invalid CSV for %s (%q): %w

Error message

invalid CSV for %s (%q): %w

What it means

parseList parses the env value as a single CSV record using encoding/csv (TrimLeadingSpace and LazyQuotes enabled). If csv.Reader.Read fails — unbalanced quotes, an odd quote in the middle of a field — the error is wrapped as 'invalid CSV for %s (%q): %w'.

Source

Thrown at config/parse.go:87

func parseList(target *[]string, env string) error {
	raw, ok, err := lookupEnv(env)
	if err != nil {
		return err
	}
	if !ok {
		return nil
	}
	if raw == "" {
		*target = []string{}
		return nil
	}
	reader := csv.NewReader(strings.NewReader(raw))
	reader.TrimLeadingSpace = true
	reader.LazyQuotes = true
	record, err := reader.Read()
	if err != nil {
		return fmt.Errorf("invalid CSV for %s (%q): %w", env, raw, err)
	}
	*target = record
	return nil
}

func parseMap(target *map[string]string, env string) error {
	raw, ok, err := lookupEnv(env)
	if err != nil {
		return err
	}
	if !ok || raw == "" {
		return nil
	}
	out := map[string]string{}
	if err := json.Unmarshal([]byte(raw), &out); err != nil {
		return fmt.Errorf("invalid JSON for %s: %w", env, err)
	}
	*target = out

View on GitHub (pinned to 14bfc25627)

Solutions

  1. Provide a plain comma-separated list without outer quotes: ALLOWED_HOSTS=a.com,b.com.
  2. Remove unbalanced or stray double quotes from the value; quote only fields that truly contain commas, and keep quotes balanced.
  3. If the value is a JSON array, convert it to CSV format or change the config field type.
  4. Use the %q raw value in the error message to see exactly which characters broke the CSV parser.

Example fix

// before
ALLOWED_HOSTS="a.com,b.com"  # literal quotes reach the parser -> CSV error
// after
ALLOWED_HOSTS=a.com,b.com
Defensive patterns

Strategy: validation

Validate before calling

func assertListEnv(env string) error {
    raw := os.Getenv(env)
    if raw == "" { return nil }
    r := csv.NewReader(strings.NewReader(strings.TrimSpace(raw)))
    r.TrimLeadingSpace = true
    r.LazyQuotes = true
    if _, err := r.Read(); err != nil {
        return fmt.Errorf("%s=%q is not valid CSV: %w", env, raw, err)
    }
    return nil
}

Try / catch

if err := config.Get(&cfg); err != nil {
    if strings.Contains(err.Error(), "invalid CSV for") {
        return fmt.Errorf("list env vars must be CSV (a,b,c), no stray quotes: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling config.Get with a list-typed env var whose value has malformed CSV quoting, e.g. ALLOWED_HOSTS='a.com,"b.com' (unclosed quote) or an embedded quote that even LazyQuotes cannot reconcile.

Common situations: Values like "a,b,c" wrapped in literal double quotes by the shell/CI so csv sees stray quotes, JSON arrays ('["a","b"]') pasted where CSV is expected, or quoting added by docker-compose variable interpolation.

Related errors


AI-assisted analysis of gotify/server@14bfc25627 (2026-09-05). Data as JSON: /api/errors/e21acedf78b97752. Report an issue: GitHub.