Skip to content

GET /api/project-health reports status:healthy with -1 node/edge counts on a store missing its tables #2232

Open

Description

@AmirF194

Version: built from source, HEAD 59a05eb
Platform: Linux (x64)
Install channel: Built from source
Binary variant: ui

What happened, and what did you expect?
GET /api/project-health always answers status: healthy, even when the project's nodes/edges tables can't be read. It calls the same cbm_store_count_nodes/cbm_store_count_edges functions handle_index_status uses, but never checks the result before writing it into the reply, so a broken store comes back as {"status":"healthy","nodes":-1,"edges":-1,...} instead of something that says the read failed.

Reproduction

  1. Build a normal project store (cbm_store_open_path + a couple of rows), then simulate corruption: sqlite3 proj.db 'DROP TABLE nodes; DROP TABLE edges;'.
  2. GET /api/project-health?name=proj
  3. Actual: {"status":"healthy","nodes":-1,"edges":-1,"size_bytes":...}. Expected: a non-healthy status, the way fix(store): report a failed COUNT read instead of returning zero #2065 handles the same failure for index_status.

I didn't drive this through the live HTTP endpoint end to end. I reproduced the exact call sequence handle_project_health makes, cbm_store_open_path_query then cbm_store_count_nodes/cbm_store_count_edges on a store whose nodes/edges tables were dropped, in a test added to test_store_nodes.c, and got -1/-1 (CBM_STORE_ERR) for both. handle_project_health (src/ui/http_server.c:1347-1374) writes those ints straight into the JSON reply with no check.

#2065 is already open for the identical gap in handle_index_status (mcp.c), adding a nodes < 0 || edges < 0 guard there. That PR doesn't touch http_server.c, so this endpoint is still open to the same false-healthy report. Happy to send a PR for the http_server.c side too, once I've got a free PR slot on this repo.

Confirmations
Searched existing issues, no duplicate found. Repro is code-only (no proprietary snippet).

Activity

  1. added
    bugSomething isn't working
    priority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.
    on Sep 19, 2026
  2. DeusData commented on Sep 19, 2026

    @DeusData
    Owner

    Thank you for the precise report and for being explicit about what was and was not exercised end to end. I checked handle_project_health on current main (59a05eb): after opening the store it puts both count results straight into a healthy response without checking for negative values. The HTTP path therefore still needs its own error handling; #2065 addresses a different caller.

    Keeping this open as a high-priority incorrect-health-reporting bug. A focused fix with a regression at the HTTP response boundary would fit the contribution guidelines. Please do not close or rework another contribution just to free a slot for this; we can review the work when capacity allows. Thank you again for identifying the separate endpoint.

    Code checked:

    static void handle_project_health(cbm_http_conn_t *c, const cbm_http_req_t *req) {
    char name[256] = {0};
    if (!cbm_http_query_param(req->query, "name", name, (int)sizeof(name)) || name[0] == '\0') {
    cbm_http_replyf(c, 400, g_cors_json, "{\"error\":\"missing name\"}");
    return;
    }
    char db_path[1024];
    db_path_for_project(name, db_path, sizeof(db_path));
    if (!cbm_file_exists(db_path)) {
    cbm_http_replyf(c, 200, g_cors_json, "{\"status\":\"missing\"}");
    return;
    }
    cbm_store_t *store = cbm_store_open_path_query(db_path);
    if (!store) {
    cbm_http_replyf(c, 200, g_cors_json, "{\"status\":\"corrupt\",\"reason\":\"cannot open\"}");
    return;
    }
    int node_count = cbm_store_count_nodes(store, name);
    int edge_count = cbm_store_count_edges(store, name);
    cbm_store_close(store);
    int64_t size = cbm_file_size(db_path);
    cbm_http_replyf(c, 200, g_cors_json,
    "{\"status\":\"healthy\",\"nodes\":%d,\"edges\":%d,\"size_bytes\":%lld}",
    node_count, edge_count, (long long)size);
    }

  3. DeusData commented on Sep 26, 2026

    @DeusData
    Owner

    Thank you for the clear report, @AmirF194, and for offering a PR! Confirmed: the project-health handler (src/ui/http_server.c around lines 1368–1376) doesn't check the counts, so -1 from a failed query is reported as "healthy". Please go ahead with your PR. Note that the UI backend is moving to the CodeAtlasWeb relaunch (feat/codeatlas-web), which has the same code, so a fix against main is still useful. Thanks!

  4. DeusData commented on Oct 19, 2026

    @DeusData
    Owner

    Thank you again for isolating the HTTP health endpoint and for being precise about the reproduction boundary. I have no new verified implementation or release status to report. The failed count must remain distinct from a healthy empty graph when the fix is reviewed.

  5. DeusData commented on Oct 25, 2026

    @DeusData
    Owner

    Thank you again for isolating the HTTP health-response boundary. The failed-count handling still needs maintainer follow-up, separately from the index_status caller. Sorry for the delay; I’ll follow up soon.

  6. cubelitblade commented on Oct 30, 2026

    @cubelitblade

    Hi @AmirF194 , I'm interested in working on this issue. Are you still planning to submit a fix for it? If not, I'd be happy to pick it up and prepare a PR. Just wanted to check first to avoid duplicating your work.

  7. Lil-Clanky commented on Nov 9, 2026

    @Lil-Clanky

    Hi @AmirF194 and @cubelitblade, are you still planning a PR for this? I have a fix ready and don't want to duplicate your work, so if one of you has something coming, I'll leave it to you. If I don't hear back in a few days, I'll open mine.

    The change is here: main...Lil-Clanky:codebase-memory-mcp:fix/2232-project-health-count-errors

    When either count read fails, /api/project-health now answers "status":"corrupt" with "reason":"cannot read node/edge counts" and leaves out nodes, edges and size_bytes. An empty project stays healthy with 0/0, so a failed count remains distinct from an empty graph. There is a regression test at the HTTP boundary that fails without the fix.

    It was written with Claude (claude-opus-5-5). I'd add the DCO sign-off myself when opening the PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingpriority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.ux/behaviorDisplay bugs, docs, adoption UX

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions