OpenNHP/opennhp · error
fail to check resource
Error message
fail to check resource: %w
What it means
loadResource wraps any os.Stat error on the resolved resource path that is NOT a 'does not exist' error with 'fail to check resource: %w'. It exists so that genuinely missing files return the distinct 'resource not found' error while permission, I/O, or path-form problems surface with their underlying cause preserved via %w. Callers (GetResource) use this to map failures onto HTTP responses.
Solutions
- Check permissions on the resource directory tree with `ls -la` and `sudo -u <serveruser> stat <path>`; fix with chmod/chown so the server user can traverse it.
- Inspect the wrapped cause (%w) in the log to see the exact errno and address it (ENOTDIR, EACCES, EIO, etc.).
- Verify baseDir configuration points at a directory that exists and is readable by the daemon.
- If on a network mount, check mount health and remount; retry the request.
- If the resource is genuinely gone, redeploy the resource file under baseDir.
Example fix
// before: any stat failure surfaces as opaque 500
if _, statErr := os.Stat(absFullPath); statErr != nil {
return nil, fmt.Errorf("fail to check resource: %w", statErr)
}
// after: handle not-a-directory like not-found for clearer client errors
if _, statErr := os.Stat(absFullPath); statErr != nil {
if os.IsNotExist(statErr) || errors.Is(statErr, syscall.ENOTDIR) {
return nil, errors.New("resource not found")
}
return nil, fmt.Errorf("fail to check resource: %w", statErr)
} Defensive patterns
Strategy: try-catch
Validate before calling
path := filepath.Join(baseDir, resourceID)
abs, _ := filepath.Abs(path)
if _, err := os.Stat(abs); err != nil {
if !os.IsNotExist(err) {
// pre-check: surface stat problem early
log.Printf("resource path unusable: %v", err)
}
} Type guard
func isStatPermissionErr(err error) bool {
return errors.Is(err, os.ErrPermission)
} Try / catch
data, err := GetResource(id, token)
if err != nil {
var statErr *os.PathError
if errors.As(err, &statErr) && !os.IsNotExist(statErr) {
// permissions/I-O issue: alert operator, return 500
}
} Prevention
- Run the daemon as a user with read access to baseDir.
- Provision resource files with mode 0644 and directories 0755.
- Avoid using files as directory components in resource IDs.
- Health-check resource availability at startup, not per request.
- Keep resources on local, reliably mounted storage.
When it happens
Trigger: os.Stat(absFullPath) fails with an error other than ENOENT — e.g. a permission error (EACCES) on the resource directory, the path is not reachable, an I/O error occurs, or a component of the path is not a directory (ENOTDIR). Called via GetResource when serving KBS resource requests.
Common situations: Resource files deployed with wrong ownership/permissions so the nhp-server process cannot stat them; the resource path contains a regular file used as a directory component; NFS/network mounts flaking; baseDir misconfigured to point into a restricted directory.
Understand the failure class
Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.
Related errors
- fail to read resource
- resource not found
- could not get file info
- keystore: create directory
- Error: fail to generating temporary file path
AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07).
Data as JSON: /api/errors/823b5096d337be28.
Report an issue: GitHub.
Appendix: source
Thrown at endpoints/server/kbs/resource/resource.go:180
}
fullPath := filepath.Join(absBaseDir, resourceID)
absFullPath, err := filepath.Abs(fullPath)
if err != nil {
return nil, fmt.Errorf("fail to get resource absolute path: %w", err)
}
// Check if the path is within the base directory to avoid path traversal attack.
if !strings.HasPrefix(absFullPath, absBaseDir) {
return nil, errors.New("invalid resource ID: potential path traversal attack")
}
if _, statErr := os.Stat(absFullPath); statErr != nil {
if os.IsNotExist(statErr) {
return nil, errors.New("resource not found")
}
return nil, fmt.Errorf("fail to check resource: %w", statErr)
}
data, err := os.ReadFile(absFullPath)
if err != nil {
return nil, fmt.Errorf("fail to read resource: %w", err)
}
return data, nil
}
func encryptWithA256GCM(key, plaintext []byte) (ciphertext, iv, tag []byte, err error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, nil, nil, err
}
gcm, err := cipher.NewGCM(block)
if err != nil {
return nil, nil, nil, errView on GitHub (pinned to 6e04ca5ff0)