All guidesMore providers: databases, auth, hosting, email and payments
On this page

Rails deploy error

Rails

Missing secret_key_base for 'production' environment

By Ohad Krispin, founder of VibeRaven · LinkedIn

"Missing secret_key_base for 'production' environment, set this string with bin/rails credentials:edit" is an ArgumentError that Rails raises at boot when it finds no secret_key_base. Rails reads the SECRET_KEY_BASE variable first, then secret_key_base in config/credentials.yml.enc, and that file opens only with config/master.key or the RAILS_MASTER_KEY variable. The Rails guide says not to commit the master key, so a host that builds from your repository does not have it. Set RAILS_MASTER_KEY to the contents of config/master.key, or set SECRET_KEY_BASE, and deploy again. If the key is set but does not match the file, the error is ActiveSupport::MessageEncryptor::InvalidMessage instead.

Where does Rails look for secret_key_base in production?

In the Rails source (railties/lib/rails/application/configuration.rb) the lookup runs in this order: SECRET_KEY_BASE_DUMMY if it is set, then the SECRET_KEY_BASE variable, then secret_key_base in the encrypted credentials. Only development and test generate a local secret when nothing is found, which is why the app boots on your laptop. In production nothing is generated, so Rails raises the error below. The real message wraps secret_key_base and the command in backticks.

The credentials file, config/credentials.yml.enc, is decrypted with config/master.key or with the RAILS_MASTER_KEY variable. The Rails security guide says to keep the master key safe and not to commit it. A host that builds your repository on its own servers therefore starts without the key.

ArgumentError: Missing secret_key_base for 'production' environment, set this string with bin/rails credentials:edit

What if the error is ActiveSupport::MessageEncryptor::InvalidMessage instead?

A key is present but it does not open the file. The comment on EncryptedFile#read in the Rails source says it raises ActiveSupport::MessageEncryptor::InvalidMessage when the content cannot be decrypted or verified. Common reasons: the value belongs to another app or another credentials file, or the file was encrypted again with a new key and the host still holds the old one. Run bin/rails credentials:show on your machine to confirm that your key and the committed file belong together, then compare it with the value on the host. Fly.io's guide shows how to read the deployed value.

With no key at all, EncryptedConfiguration returns an empty config, and you get the secret_key_base message above. If config.require_master_key is true, the Rails guide says the app does not boot without a master key, and the error says "Missing encryption key to decrypt file with".

bin/rails credentials:show
fly ssh console -C 'printenv RAILS_MASTER_KEY'

How do I set RAILS_MASTER_KEY on Render, Railway, Fly.io or Heroku?

Each host reads it as a plain environment variable. Render's Rails 8 guide says to paste the contents of config/master.key as RAILS_MASTER_KEY. Railway's Rails guide says to add SECRET_KEY_BASE or RAILS_MASTER_KEY under the service Variables, then click Deploy to apply the change; a Railway forum post about this error was marked solved after the poster found they had not deployed the changes. Fly.io's guide says fly launch extracts the master key if the project has one, and gives the command below when you set it yourself. Heroku restarts the app and creates a release whenever a config var changes.

A Docker build runs assets:precompile, which loads the app. The Rails source documents SECRET_KEY_BASE_DUMMY=1 for that step so the build does not need the real secrets, and the generated Dockerfile uses it.

# Fly.io
fly secrets set RAILS_MASTER_KEY=$(cat config/master.key)

# Heroku
heroku config:set RAILS_MASTER_KEY=$(cat config/master.key)

# Render and Railway: add RAILS_MASTER_KEY in the dashboard variables

# Dockerfile, build step only
RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile

Checklist

How to fix it, then check the fix

  1. 01Open the host's deploy log and read the first error. The message names the environment, usually 'production'. If it says something else, RAILS_ENV is not what you expect.
  2. 02
    On your machine, confirm that the key and the credentials file belong together:
    bin/rails credentials:show
  3. 03Set RAILS_MASTER_KEY on the host to the contents of config/master.key, with no extra characters. Or set SECRET_KEY_BASE to a long random value you generate. Never put either in a file you commit.
  4. 04In a Dockerfile, keep SECRET_KEY_BASE_DUMMY=1 on the assets:precompile line only. Do not copy config/master.key into the image.
  5. 05Deploy again. On Railway, click Deploy after you edit the variables; Heroku restarts on its own after a config var change.
  6. 06Open the logs: the web process boots and the health endpoint answers. The Rails 8 template names /up as the default health check endpoint.

Related

Sources

Official docs behind this checklist

FAQ

FAQ for builders before launch

Why does it work locally and fail on the host?

In development and test, Rails generates a secret and stores it in tmp/local_secret.txt when it finds none. Production never does, so the host needs the real value.

Can I use SECRET_KEY_BASE and skip the master key?

Yes. The Rails source checks the SECRET_KEY_BASE variable before the credentials file, and Railway's guide lists either variable. Other values kept in credentials.yml.enc still need the master key.

Is it safe to commit config/master.key so the host has it?

No. The Rails security guide says to keep the master key safe and not to commit it. Anyone with the key and the encrypted file can read every credential. Set it as a host variable instead.