fs.query exists()/is_dir() silently fold lfs.attributes() errors into false, contradicting their own doc comment #57

Open
opened 2026-08-16 09:23:40 +02:00 by michael · 0 comments
Owner

Problem

fs/query.lua's exists() and is_dir() collapse every
lfs.attributes() outcome into a plain boolean, discarding any
error:

function M.exists(path)
  ...
  return lfs.attributes(path, "mode") ~= nil, nil
end

function M.is_dir(path)
  ...
  return lfs.attributes(path, "mode") == "directory", nil
end

Both functions' doc comments explicitly claim:

Returns bool, nil | nil, daw_error/v1 -- always two values, so
"confirmed absent" (false) can never be confused with "could not
check" (nil, err).

But the implementation doesn't back this claim: lfs.attributes()
can return nil, err for reasons other than "path does not exist"
(e.g. EACCES on a parent directory, ELOOP on a symlink cycle). Those
cases are currently silently folded into false, nil -- "confirmed
absent" -- exactly the ambiguity the doc comment says can't happen.

read_attrs() right below handles the same lfs.attributes() failure
correctly, returning nil, daw_error/v1 (resource_id
eead0608-9fb6-4436-9972-96ecd58f8fd6). exists()/is_dir() don't use
that path.

Found while reviewing the daw_i18n/v1 migration of fs/query.lua
(DAW/daw-lua-common#48). Not an i18n issue, out of scope for #48.

Scope

  • Decide whether exists()/is_dir() should distinguish
    "confirmed absent/not-a-directory" from "attribute query failed"
    (matching their own doc comment), and if so, how

DAW/daw-lua-common#48

## Problem `fs/query.lua`'s `exists()` and `is_dir()` collapse every `lfs.attributes()` outcome into a plain boolean, discarding any error: ```lua function M.exists(path) ... return lfs.attributes(path, "mode") ~= nil, nil end function M.is_dir(path) ... return lfs.attributes(path, "mode") == "directory", nil end ``` Both functions' doc comments explicitly claim: > Returns bool, nil | nil, daw_error/v1 -- always two values, so > "confirmed absent" (false) can never be confused with "could not > check" (nil, err). But the implementation doesn't back this claim: `lfs.attributes()` can return `nil, err` for reasons other than "path does not exist" (e.g. EACCES on a parent directory, ELOOP on a symlink cycle). Those cases are currently silently folded into `false, nil` -- "confirmed absent" -- exactly the ambiguity the doc comment says can't happen. `read_attrs()` right below handles the same `lfs.attributes()` failure correctly, returning `nil, daw_error/v1` (resource_id eead0608-9fb6-4436-9972-96ecd58f8fd6). `exists()`/`is_dir()` don't use that path. Found while reviewing the daw_i18n/v1 migration of fs/query.lua (DAW/daw-lua-common#48). Not an i18n issue, out of scope for #48. ## Scope - Decide whether exists()/is_dir() should distinguish "confirmed absent/not-a-directory" from "attribute query failed" (matching their own doc comment), and if so, how ## Related DAW/daw-lua-common#48
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
DAW/daw-lua-common#57
No description provided.