conductor-oss/conductor · warning · UnsupportedOperationException
env-backed secrets are read-only
Error message
env-backed secrets are read-only
What it means
Thrown by EnvVariableSecretsDAO.putSecret when an attempt is made to write/create a secret via the env-backed secrets DAO. The env-backed DAO reads secrets exclusively from environment variables (with a configurable prefix like CONDUCTOR_SECRET_) and does not support write operations. This is an UnsupportedOperationException — a permanent limitation of the storage backend, not a transient failure.
Source
Thrown at core/src/main/java/com/netflix/conductor/core/secrets/EnvVariableSecretsDAO.java:71
@Override
public String getSecret(String name) {
return EnvVarLookup.lookup(prefix, name);
}
@Override
public boolean secretExists(String name) {
return getSecret(name) != null;
}
@Override
public List<String> listSecretNames() {
return new ArrayList<>(EnvVarLookup.allWithPrefix(prefix).keySet());
}
@Override
public void putSecret(String name, String value) {
throw new UnsupportedOperationException("env-backed secrets are read-only");
}
@Override
public void deleteSecret(String name) {
throw new UnsupportedOperationException("env-backed secrets are read-only");
}
@Override
public List<CredentialMeta> listWithMeta() {
List<CredentialMeta> result = new ArrayList<>();
EnvVarLookup.allWithPrefix(prefix)
.forEach((name, value) -> result.add(toMeta(name, value)));
for (String llmKey : KNOWN_LLM_API_KEYS) {
String value = EnvVarLookup.lookup("", llmKey);
if (value != null) {
result.add(toMeta(llmKey, value));
}
}View on GitHub (pinned to cf7c3e4a8a)
Solutions
- Set environment variables with the configured prefix (default CONDUCTOR_SECRET_) to provide secrets instead of writing through the API.
- Switch to a writable secrets backend by setting conductor.secrets.type to a supported writable implementation (e.g. database-backed DAO).
- If you need both env-sourced and API-managed secrets, configure a secrets backend that supports writes.
- Guard UI/API code paths that call putSecret with a capability check before invoking the write.
Example fix
# before — trying to write a secret via API with env backend (default) curl -X POST http://localhost:8080/api/secrets/MY_KEY -d 'value' # after — set the env var directly export CONDUCTOR_SECRET_MY_KEY=value # or switch backend in application.properties: # conductor.secrets.type=database
Defensive patterns
Strategy: type-guard
Validate before calling
// Check if the secrets backend supports writes before calling putSecret
if (secretsDAO instanceof EnvVariableSecretsDAO || secretsDAO instanceof NoopSecretsDAO) {
throw new IllegalStateException(
"Cannot write secrets with " + secretsDAO.getClass().getSimpleName()
+ " — configure a writable secrets backend");
}
secretsDAO.putSecret(name, value); Type guard
// Check write capability by testing with a no-op safe probe
public boolean canWriteSecrets(SecretsDAO dao) {
try {
// Use a marker that won't harm a real backend
// For env/noop, this throws UnsupportedOperationException
return !(dao instanceof EnvVariableSecretsDAO)
&& !(dao instanceof NoopSecretsDAO);
} catch (Exception e) {
return false;
}
} Try / catch
try {
secretsDAO.putSecret(name, value);
} catch (UnsupportedOperationException e) {
// Backend is read-only — guide the user to configure a writable backend
throw new IllegalStateException(
"Secrets backend is read-only. Set conductor.secrets.type to a writable backend.", e);
} Prevention
- Set conductor.secrets.type to a writable backend if API-based secret management is required.
- Provide secrets via environment variables (CONDUCTOR_SECRET_*) when using the env backend.
- Build a capability check into the UI/API layer to disable write buttons when the backend is read-only.
When it happens
Trigger: Calling the secrets API endpoint (POST /api/secrets/{name}) or any code path that invokes SecretsDAO.putSecret while the 'conductor.secrets.type' property is set to 'env' (which is the default). The env DAO is selected by @ConditionalOnProperty and is active by default.
Common situations: Application tries to write a secret through the API without configuring a writable secrets backend (e.g. database-backed or vault-backed). Default configuration uses env-backed secrets, which is read-only. Developer assumes the secrets API is fully functional for writes but hasn't changed conductor.secrets.type.
Related errors
- Pinecone API key is not configured. Please set conductor.vec
- env-backed environment variables are read-only
- secrets are disabled
- Skill registry is not available
- llmProvider not specified: {name}
AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14).
Data as JSON: /api/errors/b1a7e441c1669040.
Report an issue: GitHub.