ory/hydra · critical · ImmutableError
immutable configuration key "%s" was changed from "%v" to "%
Error message
immutable configuration key "%s" was changed from "%v" to "%v"
What it means
NewImmutableError builds an ImmutableError raised when a configuration key marked as immutable (must not change at runtime) receives a new value during a live reload. The error captures the key and both the old and new values, and its message states exactly what changed. It typically causes the process to terminate because continuing with a mutated immutable key would be unsafe (e.g. cryptographic secrets).
Source
Thrown at oryx/configx/error.go:24
import (
"fmt"
"github.com/pkg/errors"
)
type ImmutableError struct {
From interface{}
To interface{}
Key string
error
}
func NewImmutableError(key string, from, to interface{}) error {
return &ImmutableError{
From: from,
To: to,
Key: key,
error: errors.Errorf("immutable configuration key \"%s\" was changed from \"%v\" to \"%v\"", key, from, to),
}
}
func (e *ImmutableError) Error() string {
return fmt.Sprintf("immutable configuration key \"%s\" was changed from \"%v\" to \"%v\"", e.Key, e.From, e.To)
}
View on GitHub (pinned to 4174065ffb)
Solutions
- Restart the process after changing an immutable key instead of relying on hot reload
- Use supported secret rotation mechanisms (e.g. hydra serve with multiple valid system secrets) rather than mutating the immutable key
- Update the config in a way that avoids touching immutable keys at runtime; only modify mutable keys live
- If it fires at startup unintentionally, check for duplicate config sources (env + file) defining the key with different values
Example fix
// before # edit config.yaml system_secret in place while server is running // after $ systemctl restart hydra # apply immutable key changes via restart
Defensive patterns
Strategy: type-guard
Validate before calling
func IsImmutableConfigError(err error) bool {
var ie *configx.ImmutableError
return errors.As(err, &ie)
} Type guard
func AsImmutableError(err error) (*configx.ImmutableError, bool) {
var ie *configx.ImmutableError
ok := errors.As(err, &ie)
return ie, ok
} Try / catch
if err := serve(); err != nil {
if ie, ok := AsImmutableError(err); ok {
log.Fatalf("immutable config key %q changed (%v -> %v); restart required", ie.Key, ie.From, ie.To)
}
return err
} Prevention
- Never edit immutable keys (secrets, system secret) in watched config while running — restart instead
- Use supported rotation flows (multiple accepted secrets) rather than in-place mutation
- Separate mutable and immutable config into different files/sources
- Fail fast: treat this error as fatal and alert, since continued runtime with a changed immutable key is unsafe
When it happens
Trigger: Changing an immutable config value (commonly secrets like the system secret, cookie keys, or database DSN flagged immutable) while the application is running and a config reload (file watch, env change) picks up the new value — reload() then calls NewImmutableError.
Common situations: Rotating secrets via config file edits on a watched file; changing the system secret in Kubernetes Secrets mounted as env/files; editing hydra config in-place instead of restarting the service.
Related errors
- global secret is not configured
- global secret is too short
- a secret for signing HMAC-SHA512/256 is expected to be defin
- cookiex: purpose must be non-empty and must not contain a pi
- cookiex: at least one secret is required
AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03).
Data as JSON: /api/errors/e8d896fcab3262b8.
Report an issue: GitHub.