Troubleshooting
✅ Verified · no code on this page ·
The badge reports the whole
docs-verifysuite, not this chapter alone.
Real failures, in rough order of how often they happen.
A client cannot find the server
$ spget DEMO:TEMP
Error: Timeout("search response")
PvGetError::Timeout carries the stage it gave up at
(spvirit-client/src/types.rs:64), and the stage tells you where to look.
"search response" — nothing answered the UDP broadcast. Either no
server is running, or the search never reached it. Check, in this order:
- Is the server up?
splistwith no arguments broadcasts and lists every server that answers. - Same subnet? PVA searches go out on UDP 5076 by broadcast. Across a
router, set
EPICS_PVA_ADDR_LISTto the server's address, or pass--server host:portto skip the search entirely. - Firewall? Windows blocks inbound UDP on a new binary the first time it binds. The server starts fine and answers nothing.
- Multi-homed host? The search leaves on one interface.
spsearchshows what is actually arriving — if it shows nothing, you are on the wrong NIC.
"read header", "name server connect", "name server handshake" —
something answered, and then the TCP leg failed. The commonest cause is a
stale EPICS_PVA_NAME_SERVERS pointing at a name server that is gone: the
client goes straight to TCP, skips the broadcast, and waits. Unset it and
retry before blaming the server.
The client reads five environment variables:
EPICS_PVA_ADDR_LIST, EPICS_PVA_AUTO_ADDR_LIST, EPICS_PVA_NAME_SERVERS,
EPICS_PVA_CONN_TMO, and EPICS_PVA_ENABLE_GET_FIELD_FALLBACK.
The server is found but the PV is not
A server answers a search only for names it serves, so a timeout on one PV
while another works means the name is wrong — a typo, or a record that
failed to load. Start the server in the foreground and read the startup
line: it reports how many PVs came out of the .db file.
If the record is mbbi or mbbo and you loaded it from a .db file, it was
dropped and a message went to stderr. If it is longin or longout, it was
dropped with no message at all — the PV count in the startup line is your
only clue. See Known gaps.
Write access denied
$ spput VAC:PRESSURE 1e-5
VAC:PRESSURE ERROR protocol error: PUT init error: Write access denied
The record type is an input type. ai, bi, stringin, longin, aai
and subArray refuse writes; their output counterparts accept them. The
matrix is on Record types.
If you meant it to be writable, you wanted ao rather than ai. If you
want a simulated readback you can also poke, set SIMM — an ai in
simulation mode is writable (spvirit-server/src/types.rs:308).
The write is accepted and nothing changes
Three different causes, and they look identical from the client:
A validator rejected it. Then you get an error, not silence — check the
exit status. spput returns non-zero on a rejected write.
It is an enum. A wire PUT of an NtEnum index currently reports success
and changes nothing. Known gaps.
It is a Generic record. The Generic arm of RecordInstance::apply_put
(spvirit-server/src/apply.rs:639) is a no-op. Write it server-side with
store.put_nt().
A monitor looks frozen
The value is moving but no updates arrive. Almost always the deadband:
should_post_update (spvirit-server/src/simple_store.rs:545) suppresses
the post, not the store, when the record is a numeric scalar, MDEL is
greater than zero, the severity has not changed, and the delta is under
MDEL.
Confirm with spget — if the value has moved and the monitor has not, that
is the deadband. Set MDEL to 0 to post everything.
Two things that are not the cause: alarm transitions always post regardless
of the deadband, and ADEL is parsed and exposed but not wired into any
posting logic.
Python: on_put never fires
You attached it after Server.start(). Handles are unbound until the server
starts and bound afterwards; on_put, scan and calc must be registered
while the handle is still unbound. There is no error — the callback simply
sits there.
Register everything before you start:
temp = spvirit.ao("DEMO:SETPOINT", 20.0)
temp.on_put(lambda pv, v: print("set to", v)) # before
server = spvirit.Server([temp])
server.start() # not after
on_put fires twice for one write
Only for a rejected write, and only from spput. When the full PUT flow
fails, spput silently retries with the simple flow
(spvirit-tools/src/bin/spvirit_put.rs:214), so the server sees the write
twice. Pass --no-flow-fallback to suppress the retry — and write on_put
callbacks to be idempotent regardless.
Alarm limits are set but the severity stays NO_ALARM
Limits set through Pv::alarm_limits are published in the payload's
valueAlarm structure but never evaluated. Computed severity comes from the
server-level compute_alarms flag, which is off by default
(spvirit-server/src/server.rs:55) — spserver --compute-alarms, or
.compute_alarms(true) on the builder. See
Alarms and severity.
cargo build produced no binaries
spvirit-tools gates every binary behind a feature. A build with
--no-default-features builds the library and nothing else. See
Crate map.
spget prints 0 for a value that is not zero
That column is a display rendering, not the wire value: 5e-7 prints as
0. Use spget -F value to see the field as decoded.