Summary
kbagent sl export is completely non-functional on Windows. The snapshot builds in memory fine, but writing it to disk crashes because write_snapshot_to_file opens the output with os.O_NOFOLLOW, a POSIX-only flag that does not exist in Python on Windows.
Environment
- kbagent v0.76.1 (code present in any version with this codepath)
- Python 3.14
- Windows 11
Traceback (tail)
keboola_agent_cli/services/_semantic_layer_internals.py:1071 in write_snapshot_to_file
fd = os.open(str(output_path), os.O_WRONLY | os.O_CREAT | os.O_TRUNC | os.O_NOFOLLOW, 0o644)
AttributeError: module 'os' has no attribute 'O_NOFOLLOW'
Root cause
os.O_NOFOLLOW is POSIX-only. On Windows it isn't defined on the os module, so the os.open(...) call raises AttributeError before any write happens. The anti-symlink-follow hardening is reasonable on POSIX but must be guarded on Windows.
Suggested fix
Guard the flag so it's a no-op where unavailable:
flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
flags |= getattr(os, "O_NOFOLLOW", 0)
fd = os.open(str(output_path), flags, 0o644)
On Windows you may prefer a plain open(path, "w", encoding="utf-8") fallback — Windows lacks the symlink-follow race the flag defends against for typical user paths. If keeping os.open, also consider os.O_BINARY handling on Windows. (The 0o644 mode is ignored on Windows — harmless.)
Impact
Blocks sl export, sl diff (if it exports first), and any GitOps/versioning workflow for the semantic layer on Windows. Worked around locally with a small REST-based exporter, but the CLI command should work.
Related
Same reporter as #522 (cp1250 serve crash → fixed in #526, v0.76.1) and #528 (unreliable self-update on Windows). This is another Windows/POSIX-assumption gap.
Summary
kbagent sl exportis completely non-functional on Windows. The snapshot builds in memory fine, but writing it to disk crashes becausewrite_snapshot_to_fileopens the output withos.O_NOFOLLOW, a POSIX-only flag that does not exist in Python on Windows.Environment
Traceback (tail)
Root cause
os.O_NOFOLLOWis POSIX-only. On Windows it isn't defined on theosmodule, so theos.open(...)call raisesAttributeErrorbefore any write happens. The anti-symlink-follow hardening is reasonable on POSIX but must be guarded on Windows.Suggested fix
Guard the flag so it's a no-op where unavailable:
On Windows you may prefer a plain
open(path, "w", encoding="utf-8")fallback — Windows lacks the symlink-follow race the flag defends against for typical user paths. If keepingos.open, also consideros.O_BINARYhandling on Windows. (The0o644mode is ignored on Windows — harmless.)Impact
Blocks
sl export,sl diff(if it exports first), and any GitOps/versioning workflow for the semantic layer on Windows. Worked around locally with a small REST-based exporter, but the CLI command should work.Related
Same reporter as #522 (cp1250 serve crash → fixed in #526, v0.76.1) and #528 (unreliable self-update on Windows). This is another Windows/POSIX-assumption gap.