gotify/server · warning
cannot render config: %w
Error message
cannot render config: %w
What it means
Once the old config is decoded, Config builds the env var map (buildEnv) and renders it as .env content with godotenv.Marshal. If Marshal fails, the error is wrapped as 'cannot render config: %w'. This is rare because Marshal mostly fails on values that cannot be represented as dotenv entries.
Source
Thrown at config/migrate/migrate.go:90
}
func Config(file string) (string, error) {
if file == "" {
return "", errors.New("migrate-config requires one argument: the path to the old config.yml")
}
data, err := os.ReadFile(file)
if err != nil {
return "", fmt.Errorf("cannot read config file %s: %w", file, err)
}
var migrated oldConfig
if err := yaml.Unmarshal(data, &migrated); err != nil {
return "", fmt.Errorf("cannot parse config file %s: %w", file, err)
}
content, err := godotenv.Marshal(buildEnv(migrated))
if err != nil {
return "", fmt.Errorf("cannot render config: %w", err)
}
return content, nil
}
func buildEnv(c oldConfig) map[string]string {
out := map[string]string{}
str := func(key string, value *string) {
if value != nil {
out[key] = *value
}
}
num := func(key string, value *int) {
if value != nil {
out[key] = strconv.Itoa(*value)
}
}
boolean := func(key string, value *bool) {View on GitHub (pinned to 14bfc25627)
Solutions
- Inspect the values buildEnv produces (log the map) and quote/escape problematic values (newlines, quotes, backslashes) before Marshal.
- Upgrade or pin the godotenv dependency to a version whose Marshal handles your values.
- Sanitize values in buildEnv (e.g. strconv.Quote strings with control characters).
- As a fallback, render the map yourself with fmt.Printf("%s=%q\n", k, v) instead of godotenv.Marshal.
Example fix
// before
content, err := godotenv.Marshal(env) // fails on multiline secret
// after
for k, v := range env { env[k] = strings.ReplaceAll(v, "\n", "\\n") }
content, err := godotenv.Marshal(env) Defensive patterns
Strategy: try-catch
Validate before calling
for k, v := range envMap {
if strings.ContainsAny(v, "\n\r") {
return fmt.Errorf("value for %s contains a newline and may fail dotenv rendering", k)
}
} Try / catch
content, err := migrate.Config(oldPath)
if err != nil && strings.Contains(err.Error(), "cannot render config") {
// dump intermediate map to inspect offending values
return fmt.Errorf("rendering failed, check values for special chars: %w", err)
} Prevention
- Keep migrated values single-line; escape newlines and quotes in buildEnv
- Pin the godotenv version and read its Marshal docs for escaping rules
- Test migrate.Config against configs containing secrets with special characters
When it happens
Trigger: godotenv.Marshal returns an error while serializing the map produced by buildEnv — typically when a migrated value contains characters that cannot be represented in a dotenv file without quoting issues in the installed godotenv version.
Common situations: Old config values containing newlines or special characters that break dotenv rendering, or a godotenv library version with stricter marshaling.
Related errors
- cannot read config file %s: %w
- cannot parse config file %s: %w
- cannot delete internal application
- file with key 'file' must be present
- file must be an image
AI-assisted analysis of gotify/server@14bfc25627 (2026-09-05).
Data as JSON: /api/errors/03f4d5fa086fa463.
Report an issue: GitHub.