LearnNewsExamplesServices
Frontmatter
id11201
titleFix HealthService backup.error: fs.readdir is not a function
stateClosed
labels
bugaiai-generatedmodel-experience
assigneesneo-opus-4-7
createdAtMay 11, 2026, 2:30 PM
updatedAtMay 12, 2026, 4:08 AM
githubUrlhttps://github.com/neomjs/neo/issues/11201
authorneo-opus-4-7
commentsCount0
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
blockedBy[]
blocking[]
closedAtMay 11, 2026, 3:55 PM

Fix HealthService backup.error: fs.readdir is not a function

Closedbugaiai-generatedmodel-experience
neo-opus-4-7
neo-opus-4-7 commented on May 11, 2026, 2:30 PM

Context

Surfaced in mcp__neo-mjs-memory-core__healthcheck response 2026-05-11T12:24:20Z post-PR #11200 merge:

"backup": {
    "lastSuccessful": null,
    "count": 0,
    "error": "fs.readdir is not a function"
}

Independently corroborated by @neo-gpt's parallel healthcheck call at ~12:25Z (same backup.error payload). Non-blocker for #11181 substrate (restored-summary visibility is functionally restored via PR #11200's --apply execution at 12:20Z), but the backup-block of healthcheck is permanently broken until fixed.

The Problem

HealthService#buildBackupStateBlock (or whatever method materializes the backup healthcheck block) calls fs.readdir(...) on an object that doesn't have that method. Likely an ESM import-shape mismatch:

// Probably:
import fs from 'fs';  // CommonJS-style default; readdir is on fs.promises, not fs

// Should be:
import fs from 'fs/promises';  // ESM canonical; readdir is on fs directly

// Or:
import { promises as fs } from 'fs';  // alias-style

Backup-state observability is dead until this resolves — operators cannot verify backup-substrate health from MCP healthcheck.

The Architectural Reality

  • ai/services/memory-core/HealthService.mjs contains the #buildBackupStateBlock private method (or equivalent) that surfaces backup metadata into the healthcheck payload
  • The current implementation calls fs.readdir against a path resolved from backup-substrate config
  • The error fs.readdir is not a function indicates the runtime fs reference at the call-site is not the fs/promises namespace
  • Adjacent HealthService blocks (topology, embedding, summary providers) appear to work correctly — so the issue is isolated to backup-block import/reference

The Fix

  1. Locate the fs.readdir(...) call in HealthService.mjs (likely inside #buildBackupStateBlock or #countBackupFiles helper)
  2. Verify the fs import at the top of the file uses fs/promises (or await import('fs/promises') if dynamic)
  3. If import is already correct, the call-site may be using fs.promises.readdir(...) against a default-import fs — fix to fs.readdir(...) directly against the fs/promises named import
  4. Add unit test that mocks the backup-substrate directory + asserts healthcheck.backup returns non-error shape with valid file count

Acceptance Criteria

  • HealthService#buildBackupStateBlock calls fs.readdir correctly (no runtime error)
  • healthcheck.backup.error is null when backup substrate exists + readable
  • healthcheck.backup.count reports correct file count from JSONL backups dir
  • healthcheck.backup.lastSuccessful reports the most-recent backup's timestamp
  • Unit test covers: (a) backup dir exists with N files → non-error count, (b) backup dir missing → graceful null+0, (c) fs.readdir succeeds path

Out of Scope

  • Refactoring HealthService more broadly (other blocks work fine)
  • Adding new backup-substrate features (just restoring observability)
  • Backup execution/scheduling logic (separate concern)

Avoided Traps

  • Wholesale HealthService audit — only the backup block needs the import fix; auditing adjacent blocks would scope-creep
  • Adding a fallback default for missing backup dir — graceful skip is fine; don't fabricate backup-state when none exists

Related

  • PR #11200fix(memory-core): share core swarm summaries (#11181) — surfaced this gap empirically via the new buildChromaMigrationStats projection running healthcheck
  • 3-way cross-family V-B-A — independently corroborated by @neo-gpt + @neo-opus-4-7 healthchecks at ~12:24Z and ~12:25Z respectively

Origin Session ID

c2912891-b459-4a03-b2af-154d5e264df1

Handoff Retrieval Hints

  • query_raw_memories(query="HealthService backup error fs.readdir healthcheck")
  • File anchor: ai/services/memory-core/HealthService.mjs (search for fs.readdir or buildBackupStateBlock)
tobiu referenced in commit 0783996 - "fix(memory-core): pass fs-extra default export to buildBackupStateBlock (#11201) (#11203) on May 11, 2026, 3:55 PM
tobiu closed this issue on May 11, 2026, 3:55 PM