basecamp/kamal · error · Kamal::ConfigurationError

Secret '#{key}' not found, no secret files (#{secrets_filena

Error message

Secret '#{key}' not found, no secret files (#{secrets_filenames.join(", ")}) provided

What it means

Variant of the missing-secret error where zero secrets files were found on disk: neither .kamal/secrets-common nor .kamal/secrets/.kamal/secrets.<destination> exists (see secrets_filenames). The message lists the exact filenames Kamal looked for, so no secret reference in deploy.yml can ever be satisfied.

Source

Thrown at lib/kamal/secrets.rb:18

require "dotenv"

class Kamal::Secrets
  Kamal::Secrets::Dotenv::InlineCommandSubstitution.install!

  def initialize(destination: nil, secrets_path: ".kamal/secrets")
    @destination = destination
    @secrets_path = secrets_path
    @mutex = Mutex.new
  end

  def [](key)
    synchronized_fetch(key)
  rescue KeyError
    if secrets_files.present?
      raise Kamal::ConfigurationError, "Secret '#{key}' not found in #{secrets_files.join(", ")}"
    else
      raise Kamal::ConfigurationError, "Secret '#{key}' not found, no secret files (#{secrets_filenames.join(", ")}) provided"
    end
  end

  def to_h
    secrets
  end

  def secrets_files
    @secrets_files ||= secrets_filenames.select { |f| File.exist?(f) }
  end

  def key?(key)
    synchronized_fetch(key).present?
  rescue KeyError
    false
  end

  private

View on GitHub (pinned to eee0083b38)

Solutions

  1. Create the secrets file(s) by fetching: kamal secrets fetch -a <adapter> --account <acct> KEY_A KEY_B >> .kamal/secrets
  2. If using destinations, rerun with the right destination: kamal -d staging secrets fetch ... >> .kamal/secrets.staging (or put shared keys in .kamal/secrets-common)
  3. Run kamal from the project root (where .kamal/ lives)
  4. Bootstrap CI by storing the secrets file as a secure CI variable or fetching it from a vault in a pipeline step

Example fix

# error: Secret 'PASSWORD' not found, no secret files (.kamal/secrets-common, .kamal/secrets) provided

# fix (terminal)
kamal secrets fetch -a one_password --account me@example.com RAILS_MASTER_KEY PASSWORD >> .kamal/secrets
kamal secrets print   # verify keys resolve
Defensive patterns

Strategy: validation

Validate before calling

names = [".kamal/secrets-common", ".kamal/secrets#{ENV["KAMAL_DESTINATION"] && ".#{ENV["KAMAL_DESTINATION"]}"}]
abort "no secrets files found (looked for #{names.join(", ")}) — run kamal secrets fetch first" unless names.any? { |f| File.exist?(f) }

Prevention

When it happens

Trigger: deploy.yml uses <%= secrets.X %> on a fresh clone where .kamal/secrets* were never created (they are typically gitignored); running kamal from a directory other than the app root; a destination is active (KAMAL_DESTINATION or -d) so Kamal looks for .kamal/secrets.staging instead of .kamal/secrets.

Common situations: First deploy from a new machine or CI checkout; forgetting -d so the wrong destination file is searched; running kamal inside a subdirectory; onboarding a teammate without documenting the secrets bootstrap step.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of basecamp/kamal@eee0083b38 (2026-08-21). Data as JSON: /api/errors/76a1e647735b4534. Report an issue: GitHub.