getsops/sops · error
Failed to read %q: %w
Error message
Failed to read %q: %w
What it means
decrypt.File is a convenience wrapper that reads a local encrypted file with os.ReadFile before handing the bytes to DataWithFormat. This error wraps the os.ReadFile failure, meaning the encrypted input file could not be opened or read — sops never got to any decryption step.
Source
Thrown at decrypt/decrypt.go:24
import (
"fmt"
"os"
"time"
"github.com/getsops/sops/v3/aes"
"github.com/getsops/sops/v3/cmd/sops/common"
. "github.com/getsops/sops/v3/cmd/sops/formats" // Re-export
"github.com/getsops/sops/v3/config"
)
// File is a wrapper around Data that reads a local encrypted
// file and returns its cleartext data in an []byte
func File(path, format string) (cleartext []byte, err error) {
// Read the file into an []byte
encryptedData, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("Failed to read %q: %w", path, err)
}
// uses same logic as cli.
formatFmt := FormatForPathOrString(path, format)
return DataWithFormat(encryptedData, formatFmt)
}
// DataWithFormat is a helper that takes encrypted data, and a format enum value,
// decrypts the data and returns its cleartext in an []byte.
func DataWithFormat(data []byte, format Format) (cleartext []byte, err error) {
store := common.StoreForFormat(format, config.NewStoresConfig())
// Load SOPS file and access the data key
tree, err := store.LoadEncryptedFile(data)
if err != nil {
return nil, err
}View on GitHub (pinned to 13442bb981)
Solutions
- Verify the path exists and is a file: os.Stat / ls -la before calling decrypt.File
- Convert to an absolute path (filepath.Abs) so the call is independent of the working directory
- Check read permissions for the running user (chmod/chown or run with correct uid)
- If the data is remote (S3/GCS), fetch it yourself first and pass the bytes to decrypt.Data instead
Example fix
// before
cleartext, err := decrypt.File("secrets.enc.yaml", "yaml")
// after
abs, _ := filepath.Abs("secrets.enc.yaml")
if _, err := os.Stat(abs); err != nil {
return fmt.Errorf("encrypted file missing: %w", err)
}
cleartext, err := decrypt.File(abs, "yaml") Defensive patterns
Strategy: try-catch
Validate before calling
abs, err := filepath.Abs(path)
if err != nil {
return err
}
info, err := os.Stat(abs)
if err != nil {
return fmt.Errorf("encrypted file not readable: %w", err)
}
if info.IsDir() {
return fmt.Errorf("%s is a directory", abs)
} Try / catch
cleartext, err := decrypt.File(path, format)
if err != nil {
var perr *fs.PathError
if errors.As(err, &perr) && os.IsNotExist(perr) {
return fmt.Errorf("encrypted input %q does not exist", path)
}
return err
} Prevention
- Resolve to absolute paths before calling decrypt.File
- Stat the file in preflight when paths come from flags or env vars
- For remote data, fetch bytes yourself and use decrypt.Data instead
- Check container/CI users have read permission on mounted secret files
When it happens
Trigger: Calling decrypt.File(path, format) with a path that doesn't exist, points to a directory, or is unreadable by the current user; also when the process lacks filesystem permissions (e.g. restricted container).
Common situations: Wrong relative path after changing working directory; file deleted between write and decrypt in CI; secret file mounted with wrong permissions in Kubernetes/Docker; passing an sops URL or S3 URI where a local path is required.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- Unknown datatype: %s
- could not read config file: %s
- Failed to decrypt original mac: %w
- Failed to verify data integrity. expected mac %q, got %q
- Found non-string key %q when unflattening
AI-assisted analysis of getsops/sops@13442bb981 (2026-09-01).
Data as JSON: /api/errors/6e51b6413509dd90.
Report an issue: GitHub.