You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
backfill-fold --json aborts with SIGABRT (exit 134) and a .NET stack trace on the trimmed release — WriteCommandError and the success-path JsonSerializer.Serialize(new { ... }) both throw uncaught #181
cdidx backfill-fold --json on the published trimmed-release binary (v1.10.0) crashes with an unhandled InvalidOperationException (Reflection-based serialization disabled), prints a .NET stack trace to stderr, and exits with signal 134 (SIGABRT) — both on the success path and on every error path that goes through WriteCommandError. This is materially worse than #147's --json failure mode for status / search / files, which catches the exception and exits with the documented DbError = 3 code.
"$CDIDX" status --db /tmp/test.db --json;echo"status_ec=$?""$CDIDX" backfill-fold --db /tmp/test.db --json;echo"bf_ec=$?"
Output:
Error: database error: Reflection-based serialization has been disabled for this application. Either use the source generator APIs or explicitly configure the 'JsonSerializerOptions.TypeInfoResolver' property.
status_ec=3 ← #147: caught error, DbError exit code (still wrong but graceful)
Unhandled exception. System.InvalidOperationException: Reflection-based serialization has been disabled for this application. ...
at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_JsonSerializerIsReflectionDisabled()
at System.Text.Json.JsonSerializerOptions.ConfigureForJsonSerializer()
at System.Text.Json.JsonSerializer.Serialize[TValue](TValue, JsonSerializerOptions )
at CodeIndex.Cli.IndexCommandRunner.WriteCommandError(Boolean, JsonSerializerOptions, String, Int32, String )
at CodeIndex.Cli.IndexCommandRunner.RunBackfillFold(String[], JsonSerializerOptions)
at Program.<Main>$(String[])
/bin/bash: line 1: 16775 Aborted cdidx backfill-fold --db /tmp/test.db --json
bf_ec=134 ← SIGABRT, .NET stack trace dumped to stderr
Same crash also reproduces when triggering the success path — running backfill-fold --json against a healthy DB whose folded columns are already up to date — because the success branch also serializes an anonymous object via JsonSerializer.Serialize(new { ... }, jsonOptions). The non---json form of the same command finishes successfully:
Two places in src/CodeIndex/Cli/IndexCommandRunner.cs call JsonSerializer.Serialize(new { ... }, jsonOptions) on an anonymous type, which requires reflection-based serialization that is disabled in trimmed builds:
Both Serialize<T> calls hit JsonSerializerOptions.ConfigureForJsonSerializer() → throws InvalidOperationException because the trimmed runtime has no TypeInfoResolver. There is no surrounding try / catch in RunBackfillFold to catch this, and Program.<Main>$ doesn't appear to have a top-level catch for the backfill-fold path either, so the exception terminates the process with SIGABRT.
The other --json paths (status / search / files / etc.) probably have a wider try / catch somewhere upstream that converts the same exception into the DbError exit code, which is why #147 sees a graceful "Error: database error: ..." instead of a SIGABRT.
There's also a secondary subtlety: even after the fold serialization is fixed, the error path will fail too because WriteCommandError itself uses an anonymous object. Any --json error reporting needs a non-anonymous, source-gen-registered DTO.
Why it matters
Any CI / automation script that calls cdidx backfill-fold --json on the published binary aborts with a SIGABRT instead of receiving a structured error. The .NET stack trace is leaked to stderr.
Even on a healthy DB the success path crashes, so the documented JSON output of backfill-fold is unobtainable on the trimmed release.
The .NET stack trace leaks an internal WriteCommandError symbol with the trimming-disabled message text — confusing surface for a user who has no context for "what is JsonTypeInfo."
WriteCommandError is shared by 5 call sites in IndexCommandRunner. All 5 will exhibit the same SIGABRT under --json if their respective error conditions are triggered.
Suggested direction
Two layers; both are useful.
Layer 1 — stop the SIGABRT immediately
Wrap every --json call site in a try / catch (InvalidOperationException ex when ex.Message.StartsWith("Reflection-based serialization has been disabled")) that falls back to the human-readable error path. This converts the crash into the same observable shape as status --json on the trimmed build (graceful "Error: ..." + a non-zero exit code).
In WriteCommandError:
privatestaticintWriteCommandError(booljson,JsonSerializerOptionsjsonOptions,stringmessage,intexitCode,string?hint=null){if(json){try{Console.WriteLine(JsonSerializer.Serialize(new{status="error",message,hint},jsonOptions));returnexitCode;}catch(InvalidOperationExceptionex)when(ex.Message.Contains("Reflection-based serialization has been disabled")){// Fall through to human-readable on trimmed builds}}Console.Error.WriteLine($"Error: {message}");if(hint!=null)Console.Error.WriteLine($"Hint: {hint}");returnexitCode;}
Same shape around the success-path serialize at line 251.
This still leaves --json non-functional, but at least it's no longer SIGABRT — it matches #147's failure mode.
Wire a source-generated JsonSerializerContext for every DTO emitted by --json paths, and replace anonymous objects with named DTOs (the source generator can't see anonymous types). Specifically:
A BackfillFoldSuccessResult DTO for the success payload.
A CommandErrorResult DTO for WriteCommandError.
Both registered with [JsonSerializable(...)] on a shared [JsonSourceGenerationOptions] partial class. Once that's in place, both --json success and error paths emit real JSON on the trimmed build.
Or alternatively, disable PublishTrimmed for the release binary (#147 suggestion 1). That fixes the family without touching the call sites.
Scope
src/CodeIndex/Cli/IndexCommandRunner.cs:251 — wrap or replace anonymous-object serialize in success path.
src/CodeIndex/Cli/IndexCommandRunner.cs:683-694 (WriteCommandError) — wrap or replace anonymous-object serialize in error path.
Audit the other 4 WriteCommandError callers (lines 200, 208, 238, 277, 446) for any --json arg-handling regression once the wrap lands.
src/CodeIndex/CodeIndex.csproj — Layer 2 alternative: source-gen context or disable trimming.
tests/CodeIndex.Tests/IndexCommandRunnerTests.cs — regression: invoke backfill-fold --json and assert it doesn't Environment.FailFast / SIGABRT, and assert exit code is one of the documented CommandExitCodes.
Summary
cdidx backfill-fold --jsonon the published trimmed-release binary (v1.10.0) crashes with an unhandledInvalidOperationException(Reflection-based serialization disabled), prints a .NET stack trace to stderr, and exits with signal 134 (SIGABRT) — both on the success path and on every error path that goes throughWriteCommandError. This is materially worse than #147's--jsonfailure mode forstatus/search/files, which catches the exception and exits with the documentedDbError = 3code.Repro
Compare the two
--jsonpaths:Output:
Same crash also reproduces when triggering the success path — running
backfill-fold --jsonagainst a healthy DB whose folded columns are already up to date — because the success branch also serializes an anonymous object viaJsonSerializer.Serialize(new { ... }, jsonOptions). The non---jsonform of the same command finishes successfully:Even an unrecognized flag triggers the SIGABRT path:
Suspected root cause (from reading the source)
Two places in
src/CodeIndex/Cli/IndexCommandRunner.cscallJsonSerializer.Serialize(new { ... }, jsonOptions)on an anonymous type, which requires reflection-based serialization that is disabled in trimmed builds:Success path at
IndexCommandRunner.cs:251:Error path at
IndexCommandRunner.cs:686(WriteCommandError), called from at least 5 sites inIndexCommandRunner(lines 200, 208, 238, 277, 446):Both
Serialize<T>calls hitJsonSerializerOptions.ConfigureForJsonSerializer()→ throwsInvalidOperationExceptionbecause the trimmed runtime has noTypeInfoResolver. There is no surroundingtry / catchinRunBackfillFoldto catch this, andProgram.<Main>$doesn't appear to have a top-level catch for the backfill-fold path either, so the exception terminates the process with SIGABRT.The other
--jsonpaths (status / search / files / etc.) probably have a widertry / catchsomewhere upstream that converts the same exception into theDbErrorexit code, which is why #147 sees a graceful "Error: database error: ..." instead of a SIGABRT.There's also a secondary subtlety: even after the fold serialization is fixed, the error path will fail too because
WriteCommandErroritself uses an anonymous object. Any--jsonerror reporting needs a non-anonymous, source-gen-registered DTO.Why it matters
cdidx backfill-fold --jsonon the published binary aborts with a SIGABRT instead of receiving a structured error. The .NET stack trace is leaked to stderr.backfill-foldis unobtainable on the trimmed release.--jsonCLI crashes with misleading "Error: database error:" prefix and exit code 3 on trimmed build #147, AI agents that branch on exit codes treat exit 3 as "DB needs rebuild." Exit 134 (SIGABRT) is not inCommandExitCodesat all, so they have no documented meaning to attach — most will treat it as "unknown failure" and either retry endlessly or give up.WriteCommandErrorsymbol with the trimming-disabled message text — confusing surface for a user who has no context for "what isJsonTypeInfo."WriteCommandErroris shared by 5 call sites inIndexCommandRunner. All 5 will exhibit the same SIGABRT under--jsonif their respective error conditions are triggered.Suggested direction
Two layers; both are useful.
Layer 1 — stop the SIGABRT immediately
Wrap every
--jsoncall site in atry / catch (InvalidOperationException ex when ex.Message.StartsWith("Reflection-based serialization has been disabled"))that falls back to the human-readable error path. This converts the crash into the same observable shape asstatus --jsonon the trimmed build (graceful "Error: ..." + a non-zero exit code).In
WriteCommandError:Same shape around the success-path serialize at line 251.
This still leaves
--jsonnon-functional, but at least it's no longer SIGABRT — it matches #147's failure mode.Layer 2 — fix the underlying serialization (mirrors #147 / #178)
Wire a source-generated
JsonSerializerContextfor every DTO emitted by--jsonpaths, and replace anonymous objects with named DTOs (the source generator can't see anonymous types). Specifically:BackfillFoldSuccessResultDTO for the success payload.CommandErrorResultDTO forWriteCommandError.Both registered with
[JsonSerializable(...)]on a shared[JsonSourceGenerationOptions]partial class. Once that's in place, both--jsonsuccess and error paths emit real JSON on the trimmed build.Or alternatively, disable
PublishTrimmedfor the release binary (#147 suggestion 1). That fixes the family without touching the call sites.Scope
src/CodeIndex/Cli/IndexCommandRunner.cs:251— wrap or replace anonymous-object serialize in success path.src/CodeIndex/Cli/IndexCommandRunner.cs:683-694(WriteCommandError) — wrap or replace anonymous-object serialize in error path.WriteCommandErrorcallers (lines 200, 208, 238, 277, 446) for any--jsonarg-handling regression once the wrap lands.src/CodeIndex/CodeIndex.csproj— Layer 2 alternative: source-gen context or disable trimming.tests/CodeIndex.Tests/IndexCommandRunnerTests.cs— regression: invokebackfill-fold --jsonand assert it doesn'tEnvironment.FailFast/ SIGABRT, and assert exit code is one of the documentedCommandExitCodes.Related
--jsonCLI crashes with misleading "Error: database error:" prefix and exit code 3 on trimmed build #147 —--jsonCLI broken on trimmed release. Same root cause, gentler observable failure (caught error vs. SIGABRT). This issue is the "andbackfill-foldis even worse" companion.tools/listis silently dropped (no JSON-RPC error response) on the trimmed release binary — AI clients hang on the first handshake step #178 — MCPtools/listsilently dropped on trimmed release. Same family.Environment
install.sh—PublishTrimmed=true).cdidx index ...— repro doesn't depend on DB contents, the crash is in the JSON output path.CLOUD_BOOTSTRAP_PROMPT.md.