Skip to content

fix: replace sync fs calls in async contexts and silent catch blocks #683

Description

@avoidwork

Summary

The src/ audit found 14 issues across 104 files: 3 high-severity blocking operations in async contexts, 9 medium-severity sync FS calls in async call chains, and 20+ silent catch blocks violating AGENTS.md §1.1.

Environment

  • OS: Linux 7.0.14-5-pve
  • Node.js: v25.8.1
  • madz version: 1.38.15
  • LLM provider: Unknown — user to confirm

Reproduction

Run the audit tool or manually grep for sync FS calls in async contexts:

  1. Check src/memory/context.jsloadContext() uses readFileSync/readdirSync
  2. Check src/memory/prompts.jsloadSystemPrompt() uses readFileSync
  3. Check src/skills/registry.jsgetSkillBody() uses readFileSync
  4. Verify these are called from async contexts (scheduler, deepAgents, TUI)

Expected Behavior

  • No blocking operations in async functions (per AGENTS.md §1.1)
  • All catch blocks should log or re-throw errors (per AGENTS.md §1.1)

Actual Behavior

  • 3 high-severity files use sync FS in async call chains
  • 9 medium-severity files use sync FS in async call chains
  • 20+ silent catch blocks across the codebase

Additional Context

Full audit details:

High Severity — Blocking Operations in Async Contexts

File Line Issue
src/memory/context.js 1-95 readFileSync/readdirSync in loadContext() — called from async src/scheduler/scheduler.js:198 and async src/agent/deepAgents.js:126 (via loadSystemPrompt)
src/memory/prompts.js 1-33 readFileSync in loadSystemPrompt() — called from async src/agent/deepAgents.js:126, async src/scheduler/scheduler.js:198, and async src/tui/app.js:368,488
src/skills/registry.js 154-163 readFileSync in getSkillBody() — called from async src/tools/skills.js:80 (skillViewImpl)

Medium Severity — Sync FS in Files Called from Async Contexts

File Lines Issue
src/memory/reader.js 52 readFileSync in readMemoryFile() — called from async src/tools/session_search.js:78,83,204
src/memory/writer.js 30,57 mkdirSync/writeFileSync in writeMemoryFile() — called from async src/tools/sampling.js:64 (via writeFile), async src/tools/skills.js:268
src/session/loader.js 1-77 readFileSync/readdirSync/statSync in loadSession() — called from async src/session/factory.js
src/memory/profile.js 67,92 readFileSync/writeFileSync/mkdirSync in loadProfile()/saveProfile() — called from async src/session/onboarding.js:192
src/sandbox/runner.js 43,46 existsSync/readFileSync in detectShebang() — called from async sandbox execution path
src/skills/discoverer.js 1-219 readFileSync/readdirSync/statSync/existsSync in discoverSkills() — called from async src/skills/registry.js:37 (discover())
src/memory/retention.js 1-68 readFileSync/readdirSync/statSync/unlinkSync in cleanRetainedMemory()/enforceMaxEntries() — check callers for async usage
src/config/loader.js 147,169 readFileSync/writeFileSync in loadConfig()/setConfigValue() — module-level init + sync function, imported by async files

Medium Severity — Silent Catch Blocks (AGENTS.md §1.1)

AGENTS.md §1.1 prohibits catch (err) {} empty or silent catch blocks. The following use bare catch {} with no logging:

File Line Pattern
src/memory/retention.js 29,63 catch {} — silently skips directory errors in retention cleanup
src/memory/expireEphemeral.js 23,52,64 catch {} — silently skips read errors, directory errors, and deletion errors
src/scheduler/scheduler.js 65,69,197,200 catch {} — silently skips schedule load, run, and context load failures
src/scheduler/cron.js 429,432,439,475,479 catch {} — silently skips readdir, mkdir, readFile, and job read failures
src/skills/discoverer.js 42,57,81,94,172 catch {} — silently skips YAML parse, stat, and directory errors
src/agent/agents/*.js 17 (×9 files) catch {} — silently returns "" when prompt files are missing (coding, debug, documentation, code-review, search, security-audit, performance, testing, research)
src/tui/contextTokens.js 21,40 catch {} — silently returns 0 on token calculation errors
src/tui/statusBar.js 35 catch {} — silently hides status bar errors
src/workspace/loadAgents.js 16 catch {} — silently skips AGENTS.md load failures

Low Severity — Minor

File Line Issue
src/logger.js 27 readFileSync for Alpine detection — acceptable (module-level init, not async)
src/logger.js 135 TODO comment about pino.multistream deprecation — noted, not actionable now

Summary

  • 10 files use synchronous fs operations (readFileSync, writeFileSync, readdirSync, statSync, existsSync, mkdirSync, unlinkSync)
  • 7 of those are called from async contexts (directly or transitively)
  • 20+ silent catch blocks across the codebase violate AGENTS.md §1.1
  • No hardcoded secrets, eval(), SQL injection vectors, or wildcard exports found
  • No console.log() in production code

Metadata

Metadata

Assignees

No one assigned

    Labels

    approvedAn identifier for Madz to take action.bugSomething isn't workingin progress

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions