Bug Description
When using the HTTP API (POST /v1/query), variables created with +variable in one request cannot be recalled in a subsequent request. The second request panics at construct.rs:217 with called Option::unwrap() on a None value, which poisons the internal Mutex and makes the server unresponsive to all further requests (every subsequent request returns PoisonError).
Environment
- Positorium v0.1.4 (built from master, commit
HEAD)
- Platform: WSL2 Ubuntu, Linux 6.6.87
- Rust: 1.92.0
Steps to Reproduce
# Start fresh
rm -f positorium.db && ./target/release/positorium &
sleep 4
# Request 1: create a role and a thing — WORKS
curl -s http://127.0.0.1:8080/v1/query \
-H "Content-Type: application/json" \
-d '{"script":"add role name; add posit [{(+alice, name)}, \"Alice\", '\''2024-01-01'\''];","stream":false}'
# Returns: {"status":"ok",...}
# Request 2: recall the same variable — PANICS
curl -s http://127.0.0.1:8080/v1/query \
-H "Content-Type: application/json" \
-d '{"script":"add posit [{(alice, name)}, \"Alice Updated\", '\''2025-01-01'\''];","stream":false}'
# Returns: "Join error" (HTTP 500)
# Server log: thread 'tokio-runtime-worker' panicked at src/construct.rs:217:40
Expected Behavior
Either:
- Variables from previous requests are accessible in subsequent requests (session-like behavior), OR
- A clear error message like "Unknown variable 'alice'" instead of a panic
Actual Behavior
construct.rs:217 panics with unwrap() on None
- The panic poisons the
Mutex, making the entire server permanently unresponsive
- All subsequent requests (even valid ones) return
PoisonError
- The only recovery is to restart the process
Workaround
Combine all posits that share variables into a single request using comma-separated syntax:
# This works — both posits in one script, variable persists within execution
curl -s http://127.0.0.1:8080/v1/query \
-H "Content-Type: application/json" \
-d '{"script":"add role name; add posit [{(+alice, name)}, \"Alice\", '\''2024-01-01'\''], [{(alice, name)}, \"Alice Updated\", '\''2025-01-01'\''];","stream":false}'
Additional Context
The startup script path (traqula_file_to_run_on_startup) does not have this issue because it executes in a single Engine context. The bug is specific to the HTTP server path where each request creates a fresh Engine instance, so variables from previous requests are not in scope.
The Mutex poisoning is a secondary issue — even if the variable recall is expected to fail, the panic should be caught and returned as an error response rather than crashing the thread and poisoning shared state.
Suggested Fix
- In
construct.rs:217, replace .unwrap() with .ok_or(DatabaseError::Execution {...}) to return an error instead of panicking
- In
server.rs, wrap the engine execution in std::panic::catch_unwind() to prevent Mutex poisoning from unhandled panics
Thank you for building Positorium — it's a remarkable piece of work. We're using it as the bitemporal evidence layer in a compliance automation pipeline alongside TypeDB and Alloy 6.
Bug Description
When using the HTTP API (
POST /v1/query), variables created with+variablein one request cannot be recalled in a subsequent request. The second request panics atconstruct.rs:217withcalled Option::unwrap() on a None value, which poisons the internal Mutex and makes the server unresponsive to all further requests (every subsequent request returnsPoisonError).Environment
HEAD)Steps to Reproduce
Expected Behavior
Either:
Actual Behavior
construct.rs:217panics withunwrap()onNoneMutex, making the entire server permanently unresponsivePoisonErrorWorkaround
Combine all posits that share variables into a single request using comma-separated syntax:
Additional Context
The startup script path (
traqula_file_to_run_on_startup) does not have this issue because it executes in a singleEnginecontext. The bug is specific to the HTTP server path where each request creates a freshEngineinstance, so variables from previous requests are not in scope.The Mutex poisoning is a secondary issue — even if the variable recall is expected to fail, the panic should be caught and returned as an error response rather than crashing the thread and poisoning shared state.
Suggested Fix
construct.rs:217, replace.unwrap()with.ok_or(DatabaseError::Execution {...})to return an error instead of panickingserver.rs, wrap the engine execution instd::panic::catch_unwind()to prevent Mutex poisoning from unhandled panicsThank you for building Positorium — it's a remarkable piece of work. We're using it as the bitemporal evidence layer in a compliance automation pipeline alongside TypeDB and Alloy 6.