sipeed/picoclaw · error
credential: file:// reference has no filename
Error message
credential: file:// reference has no filename
What it means
Returned by Resolver.Resolve when a credential value starts with `file://` but the remainder is empty or only whitespace. The file scheme promises an indirection ("read the secret from this file in the config dir"), so a bare scheme with no filename is a malformed reference, not a lookup miss. Empty-string credentials short-circuit earlier, so this only fires for literal `file://` (or `file:// `).
Source
Thrown at pkg/credential/credential.go:119
}
}
return &Resolver{configDir: configDir, resolvedConfigDir: resolved}
}
// Resolve returns the actual credential value for raw:
//
// - "" → "" (no error; auth_method=oauth needs no key)
// - "file://name.key" → trimmed content of configDir/name.key
// - anything else → raw unchanged (plaintext credential)
func (r *Resolver) Resolve(raw string) (string, error) {
if raw == "" {
return "", nil
}
if strings.HasPrefix(raw, FileScheme) {
fileName := strings.TrimSpace(strings.TrimPrefix(raw, FileScheme))
if fileName == "" {
return "", fmt.Errorf("credential: file:// reference has no filename")
}
baseDir := r.resolvedConfigDir
if baseDir == "" {
baseDir = r.configDir
}
keyPath := filepath.Join(baseDir, fileName)
// Resolve symlinks before enforcing containment to prevent escaping via symlinks.
realKeyPath, err := filepath.EvalSymlinks(keyPath)
if err != nil {
return "", fmt.Errorf("credential: failed to resolve credential file path %q: %w", keyPath, err)
}
if !isWithinDir(realKeyPath, baseDir) {
return "", fmt.Errorf("credential: file:// path escapes config directory")
}
data, err := os.ReadFile(realKeyPath)
if err != nil {
return "", fmt.Errorf("credential: failed to read credential file %q: %w", realKeyPath, err)View on GitHub (pinned to 49183d7e8d)
Solutions
- Complete the reference: `file://name.key` where name.key lives in the config dir
- If you meant an empty credential (e.g. oauth), use an empty string instead of file://
- Check templating/envsubst output for unfilled ${...} placeholders that leave file:// bare
Example fix
# before api_key: file:// # after api_key: file://openai.key
Defensive patterns
Strategy: validation
Validate before calling
// Validate file:// references before resolving.
func fileRefHasName(raw string) error {
if strings.HasPrefix(raw, "file://") {
if strings.TrimSpace(strings.TrimPrefix(raw, "file://")) == "" {
return fmt.Errorf("file:// reference %q has no filename", raw)
}
}
return nil
} Type guard
func isCompleteFileRef(raw string) bool {
if !strings.HasPrefix(raw, "file://") { return true }
return strings.TrimSpace(strings.TrimPrefix(raw, "file://")) != ""
} Try / catch
val, err := resolver.Resolve(raw)
if err != nil {
if strings.Contains(err.Error(), "no filename") {
// config authoring bug — fail fast with config file/line context
}
return "", err
} Prevention
- Fail template rendering when ${...} placeholders are unfilled
- Lint configs for bare `file://` values
- Remember empty credential = empty string, not file://
When it happens
Trigger: Config contains `api_key: file://` or `api_key: "file:// "`. strings.TrimPrefix strips the scheme, TrimSpace removes whitespace, and the empty remainder triggers the error.
Common situations: Template placeholders left unfilled (`api_key: file://${KEY_FILE}`), users writing file:// intending "use some file" without knowing the filename is required, or trailing- edit accidents deleting the filename.
Related errors
- credential: credential file %q is empty
- invalid WeCom QR generate URL: %w
- invalid WeCom QR query URL: %w
- invalid WeCom QR page URL: %w
- api key is required
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/9b758afad228212f.
Report an issue: GitHub.