-
Notifications
You must be signed in to change notification settings - Fork 0
Troubleshooting
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 --versionIf SOPS is installed to a non-standard location, point Keyseal to it in keyseal.yaml:
sops:
binary: /usr/local/bin/sopsThen rerun the mutating command. Production/deploy machines that only render or exec secrets do not need this fix.
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/ageThen rerun:
keyseal doctorEvery 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 initThe 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-toplevelIf that fails, change into the correct repository or initialize one yourself with git init. Keyseal does not create the Git repository for you.
Keyseal shells out to the git binary for status, diff, history, commit, rollback, and updatekeys --commit behavior.
Fix:
git --versionIf Git is installed in a non-standard location, ensure it is available on PATH before you run Keyseal.
After keyseal init, the generated .sops.yaml contains:
age: age1REPLACE_ME,age1RECOVERY_REPLACE_MESOPS 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.yamlSOPS 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$"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/appDo not commit a plaintext .enc.yaml file to the repository.
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.
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 0600Or if you genuinely need a less restrictive mode for your deployment:
keyseal render production/platform/app --out ./app.env --mode 0644 --forceKeyseal validates the decrypted secret document after every decrypt. Common causes:
- A key in
valuesdoes not matchvalidation.key_pattern(default requires uppercase + digits + underscores only). This is usually a key with a lowercase letter or a hyphen. - The
valuesmap is empty andvalidation.require_valuesistrue. - The document has
version: 0or is missingversion.
Fix: Run keyseal edit <logical-name> to fix the document, or adjust validation.key_pattern in keyseal.yaml if lowercase keys are intentional.
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 doctorProduction/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.
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.
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/appkeyseal 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 statusIf the file is unchanged, there is nothing for Keyseal to commit.
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.
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 --jsonError: 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 |
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.
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/keysealVerify the checksum before using the binary:
sha256sum -c keyseal_v1.0.0_checksums.txt --ignore-missingYour 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:
-
SOPS_AGE_KEY_FILEfrom the environment -
sops.age_key_filefromkeyseal.yaml - 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 --stdoutDoctor reports decrypt errors from the same SOPS Go library path used by render and exec.
Getting Started
Reference
Operations
Development