Skip to content

Troubleshooting

Jake Paine edited this page May 23, 2026 · 5 revisions

Troubleshooting

sops: command not found or SOPS binary error

Only mutating operations call the external sops binary. keyseal add, keyseal edit, and keyseal updatekeys fail if it is not on your PATH or configured with a valid explicit path. Read-only render, exec, doctor, and verify use the official SOPS Go decrypt library and do not require external sops.

Fix for developer/admin machines: Install SOPS and verify it works:

sops --version

If SOPS is installed to a non-standard location, point Keyseal to it in keyseal.yaml:

sops:
  binary: /usr/local/bin/sops

Then rerun the mutating command. Production/deploy machines that only render or exec secrets do not need this fix.


age binary message

Doctor reports sops.age_binary as admin setup context. The external age CLI is useful for generating or inspecting keys, but read-only decrypt operations need age private key material, not the age CLI. Production servers do not need age installed just to run render, exec, doctor, or verify.

If this is a developer/admin machine and you need key generation, install age or point Keyseal at the right binary:

sops:
  age_binary: /usr/local/bin/age

Then rerun:

keyseal doctor

keyseal.yaml not found in <cwd>; run keyseal init first

Every command except init looks for keyseal.yaml in the current working directory. You are either in the wrong directory or the file does not exist.

Fix:

# confirm you are in the right directory
ls keyseal.yaml

# if it does not exist, initialize
keyseal init

not inside a Git repository

The Git-aware commands (status, diff, history, commit, rollback, plus commit-enabled add, edit, and updatekeys) require that your current working directory is inside an existing Git repository.

Fix:

git rev-parse --show-toplevel

If that fails, change into the correct repository or initialize one yourself with git init. Keyseal does not create the Git repository for you.


git binary not found

Keyseal shells out to the git binary for status, diff, history, commit, rollback, and updatekeys --commit behavior.

Fix:

git --version

If Git is installed in a non-standard location, ensure it is available on PATH before you run Keyseal.


Placeholder recipients in .sops.yaml

After keyseal init, the generated .sops.yaml contains:

age: age1REPLACE_ME,age1RECOVERY_REPLACE_ME

SOPS will not encrypt with these values. Doctor will flag them as failures.

Fix: Replace with real age public keys:

# if you need to generate a key pair
age-keygen -o ~/.config/sops/age/keys.txt
# note the public key from the output, then edit .sops.yaml

sops encrypt fails with "no matching creation rules"

SOPS cannot find a creation rule in .sops.yaml that matches the target file path.

Common cause: The path_regex in your creation rule does not match the path you are trying to encrypt. The regex is matched against the final destination path, or the --filename-override value passed by keyseal add.

Example: if your target is production/platform/app.enc.yaml but your rule is:

path_regex: production/platform/.*\.enc\.yaml$

and you have repository.root: ., the path passed to SOPS is relative to where you ran keyseal add. Verify the regex with:

# test the regex against your path
echo "production/platform/app.enc.yaml" | grep -E "production/platform/.*\.enc\.yaml$"

Plaintext file at an .enc.yaml path

Doctor will report:

[fail] production/platform/app.enc.yaml: is non-empty plaintext at an encrypted path

This means the file at that path contains non-empty content but has no SOPS metadata. Keyseal treats that as a plaintext-at-encrypted-path failure even if the content is malformed, because non-empty plaintext secret content must not be ignored.

How this happens: The file was written manually or copied from an example without going through keyseal add or sops encrypt.

Fix:

# remove the plaintext file
rm production/platform/app.enc.yaml

# recreate it properly
keyseal add production/platform/app

# then edit to set real values
keyseal edit production/platform/app

Do not commit a plaintext .enc.yaml file to the repository.


Empty or whitespace-only .enc.yaml placeholder file

Doctor will report a warning and skip decrypt validation for an empty or whitespace-only .enc.yaml file.

This is meant for uninitialized placeholder files that exist in the tree but have not been populated yet.

keyseal render and keyseal exec will skip these files when other requested secrets are usable. If every requested secret is an empty placeholder, the command fails with a clear error instead of silently producing empty output.

keyseal edit <logical-name> can bootstrap the empty file with an encrypted starter document and then open it in SOPS.


render refuses to write because mode is unsafe

Error: mode 0644 is not owner-only; use --force to override

The file mode you specified (or the default in keyseal.yaml) would give read access to group or world users.

Fix: Use 0600 (the default):

keyseal render production/platform/app --out /run/secrets/app.env --mode 0600

Or if you genuinely need a less restrictive mode for your deployment:

keyseal render production/platform/app --out ./app.env --mode 0644 --force

render or exec fails with schema validation error

Keyseal validates the decrypted secret document after every decrypt. Common causes:

  • A key in values does not match validation.key_pattern (default requires uppercase + digits + underscores only). This is usually a key with a lowercase letter or a hyphen.
  • The values map is empty and validation.require_values is true.
  • The document has version: 0 or is missing version.

Fix: Run keyseal edit <logical-name> to fix the document, or adjust validation.key_pattern in keyseal.yaml if lowercase keys are intentional.


SOPS compatibility warning about possibly unencrypted comments

The SOPS Go library can warn about older encrypted files that contain comments it cannot decrypt, for example:

Found possibly unencrypted comment in file

Keyseal deliberately does not print this warning during render or exec, because those commands may feed plaintext directly into deployment scripts or environment files. Instead, keyseal doctor and keyseal verify capture the warning and show it as a structured warning for the affected secret.

Fix: On a developer/admin machine with the external SOPS CLI installed, open and save or re-encrypt the file with a current SOPS release:

keyseal edit production/platform/app
keyseal doctor

Production/deploy machines still do not need the external sops or age binaries for read-only decrypt/render/exec usage. Servers need the age key, not the age CLI.


keyseal add fails with "unknown template"

Error: unknown template "my-template"

Only four templates exist: laravel, stripe, mail, mysql-app. Template names are case-sensitive.

Fix: Check the available templates in Templates or omit --template to use the default single-key starter.


keyseal add fails with "file already exists"

The target .enc.yaml file already exists and you did not pass --force.

Fix:

# overwrite the existing file
keyseal add production/platform/app --force

# or just edit the existing file
keyseal edit production/platform/app

nothing to commit

keyseal commit returns this when no Keyseal-managed files currently differ from Git history.

The same message can appear on edit --commit, rollback --commit, or updatekeys --commit when the command completed but did not leave any change to stage.

Fix: Check the filtered status view first:

keyseal status

If the file is unchanged, there is nothing for Keyseal to commit.


target file has local changes

keyseal rollback refuses to overwrite a secret file that already has staged or unstaged local changes.

Fix: Either commit or discard the local change first, then retry the rollback.

To inspect the target rollback safely:

keyseal rollback production/platform/app --to <commit> --dry-run

--dry-run is preview-only and does not require the target file to be clean.


keyseal doctor exits 1 with no visible error

Doctor exits 1 when any check has status fail. The failure is printed to stdout, not stderr. If you are running in a context that suppresses stdout, redirect it:

keyseal doctor 2>&1
# or use JSON to separate structured output
keyseal doctor --json

Logical name validation errors

Error: invalid logical name "production/platform/app.enc.yaml": name must not end with .yaml

Common logical name mistakes:

Bad input Problem
production/platform/app.enc.yaml Do not include the file extension
/production/platform/app Logical names must be relative
production/../platform/app No path traversal
production//platform/app No empty segments

Build produces version dev

If you build without make build (e.g. go build ./cmd/keyseal), the ldflags that inject version metadata are not set. The binary will report keyseal dev.

Fix: Always use make build or make dist for any build you care about the version string of.


Release archive extraction issues

Each release archive contains the binary, README.md, and LICENSE in a top-level directory named after the archive. Extract with:

tar xzf keyseal_v1.0.0_linux_amd64.tar.gz
# produces: keyseal_v1.0.0_linux_amd64/keyseal

Verify the checksum before using the binary:

sha256sum -c keyseal_v1.0.0_checksums.txt --ignore-missing

Decryption fails with "no key was able to decrypt"

Your age private key is not at the location Keyseal/SOPS expects, or the file was encrypted with a different key. Servers need the age key, not the age CLI.

Keyseal resolves the age key path in this order:

  1. SOPS_AGE_KEY_FILE from the environment
  2. sops.age_key_file from keyseal.yaml
  3. SOPS default lookup

Check:

# check the env var
echo $SOPS_AGE_KEY_FILE

# inspect the configured fallback path
grep -A2 '^sops:' keyseal.yaml

# verify Keyseal can see the configured key
keyseal render production/platform/app --stdout

Doctor reports decrypt errors from the same SOPS Go library path used by render and exec.

Clone this wiki locally