What Happened
evercli treats any HTTP response whose body parses as JSON with status:0 (zero-value / missing field) as success, regardless of the actual HTTP status code. A 500 (or any non-2xx) whose body is envelope-shaped but lacks an explicit status is swallowed — callers see err == nil, checkpoints advance, and users are told the operation succeeded when the backend never recorded anything.
Root cause: json.Unmarshal fills missing fields with the zero value, so any valid JSON body that is envelope-shaped but does not carry an explicit non-zero status is indistinguishable from a real success. The env.Status == 0 branch never inspects resp.StatusCode.
Location: cli/internal/client/http_client.go — (*httpClient).do, around lines 274–289:
var env backendEnvelope
if err := json.Unmarshal(raw, &env); err != nil {
// ... correctly classifies non-JSON bodies by HTTP status ...
}
if env.Status == 0 { // ← no resp.StatusCode check here
if out != nil && len(env.Result) > 0 && string(env.Result) != "null" {
if err := json.Unmarshal(env.Result, out); err != nil {
return output.Internal(fmt.Errorf("decode result: %w", err))
}
}
return nil // ← HTTP 500 also lands here
}
return classifyEnvelopeError(env)
Steps To Reproduce
- Start a local
httptest/mock server that returns HTTP 500 with body:
{"requestId":"req-500","result":{}}
- Point the CLI at it (
EVERCLI_API_BASE_URL=http://127.0.0.1:<port>).
- Call any client method (e.g.
auth login --api-key, plugin install, import run).
- Observe: the call returns success (
err == nil) even though the server returned 500.
Expected Behavior
Non-2xx responses must never be treated as success. The env.Status == 0 branch should only apply to 2xx responses; otherwise the error should be classified by HTTP status.
Suggested Fix
if resp.StatusCode/100 != 2 {
return output.Upstream(resp.StatusCode, http.StatusText(resp.StatusCode), "")
}
Plus a regression test covering "HTTP 500 + envelope-shaped JSON with status:0".
Impact
- Silent data loss:
import run uploads → CreateRecord fails with 500 + partial JSON → CLI reports success → checkpoint advances to uploaded → the memory is never stored and a re-run cannot recover it.
plugin install may silently skip RegisterAgent failures.
- Every API call path is affected.
Environment
- OS: macOS 26.4 (arm64)
evercli --version: 0.31.2
- Package or plugin:
@everme/cli / evercli (Go CLI)
Logs
No real emk_*/evt_* values used in this report; all examples are synthetic.
What Happened
everclitreats any HTTP response whose body parses as JSON withstatus:0(zero-value / missing field) as success, regardless of the actual HTTP status code. A 500 (or any non-2xx) whose body is envelope-shaped but lacks an explicitstatusis swallowed — callers seeerr == nil, checkpoints advance, and users are told the operation succeeded when the backend never recorded anything.Root cause:
json.Unmarshalfills missing fields with the zero value, so any valid JSON body that is envelope-shaped but does not carry an explicit non-zerostatusis indistinguishable from a real success. Theenv.Status == 0branch never inspectsresp.StatusCode.Location:
cli/internal/client/http_client.go—(*httpClient).do, around lines 274–289:Steps To Reproduce
httptest/mock server that returns HTTP 500 with body:{"requestId":"req-500","result":{}}EVERCLI_API_BASE_URL=http://127.0.0.1:<port>).auth login --api-key,plugin install,import run).err == nil) even though the server returned 500.Expected Behavior
Non-2xx responses must never be treated as success. The
env.Status == 0branch should only apply to 2xx responses; otherwise the error should be classified by HTTP status.Suggested Fix
Plus a regression test covering "HTTP 500 + envelope-shaped JSON with status:0".
Impact
import runuploads →CreateRecordfails with 500 + partial JSON → CLI reports success → checkpoint advances touploaded→ the memory is never stored and a re-run cannot recover it.plugin installmay silently skipRegisterAgentfailures.Environment
evercli --version: 0.31.2@everme/cli/evercli(Go CLI)Logs
No real
emk_*/evt_*values used in this report; all examples are synthetic.