Technical Troubleshooting
Common symptoms / errors and their solutions. Quick classification → detailed resolution flow.
status.sh— One-line summary of container + port + API + key app.propertieshealth.sh— Comprehensive health check based on exit codes (suitable for cron)doctor.sh— Diagnostic tarball for support escalation (api / docker / systemd / 7 component logs / redacted config / host metrics)/api/v1/system/health— Status map for 8 components + 503 branching (immediately identify which component is DOWN)- Container Mode Operations — Failure response + command cheat sheet
Symptom Index
| Symptom | Candidate Cause |
|---|---|
| App stops during boot | Cassandra connection failure, DDL application failure |
/api/v1/edge response is started=false | Collector initialization failure (driver / cache issue) |
Specific OPC only connection_status=DISCONNECTED | PLC network / authentication / address format |
| All OPCs occasionally disconnect simultaneously | Full restart of OPCUAServerManager due to OPC add/modify |
| MQTT publish not working | mqtt.enable=false or broker authentication failure |
| Sparkplug topic not published | sparkplug.enable=false or missing jar |
| Screen loads slowly | opcList() N+1 queries + accumulated sleep |
| OPC startup takes 5 seconds each | Thread.sleep impact (Phase A1 target) |
Boot / Initialization
Cassandra Connection Failure
Caused by: com.datastax.oss.driver.core.exceptions.NoHostAvailableException
| Check | What to Verify |
|---|---|
| Cassandra running | nodetool status |
| Port reachability | telnet <app.db.host> 9042 |
| Keyspace exists | After cqlsh -u cassandra -p cassandra, run DESCRIBE KEYSPACE pe; |
app.db.* matches oltp.cassandra.* | Review both entries in app.properties |
app.sql.path has a typo in resouces
The resouces in the app.sql.path = classpath:resouces/sql of app.properties has a typo, but it works because the directory
is maintained with the same name. If you get an error saying SQL resources cannot be found, verify that
the WEB-INF/resouces/sql/ path actually exists.
OPC / Drivers
Specific OPC Connection Failed
| Protocol | First Check |
|---|---|
| OPCUA | opc_agent_port reachability, try discovery=true, user/password |
| Modbus TCP | Port 502 reachability, holding-register:... format |
| MELSEC | MC protocol active, controller-type=Q_L match |
| S7 | Rack/slot match, "PUT/GET" active |
| LS | If NetUtils.isReachable fails, suspect ICMP blocking, port 2004 |
| EIP | Rack/slot, port 44818 |
Refer to the "Common Errors + Solutions" table on each driver page first.
LS-PLC Ping failed
The LS driver checks reachability via ICMP ping before connecting. If ICMP is blocked on the corporate network, even a healthy PLC will be reported as failed.
Resolution:
- Allow ICMP in the firewall
- Or, disable the ping check via option in
LSDriver.connect()in a future change (currently requires a code change)
32-bit / 64-bit Value Mismatch
This is mostly caused by format not specified.
| Protocol | Incorrect Pattern → Correct Pattern |
|---|---|
| LS | D00600 + Integer (read as 16-bit) → D00600 + Integer + format=DW |
| Modbus | holding-register:1 (16-bit) → holding-register:1:DINT |
| S7 | %DB1.DBW0 + Float → %DB1.DBD0 + format=REAL |
32-bit Float Value is NaN / a Large Number
This is a byte order (endianness) issue. Check the byte/word swap policy on the slave / master:
- For Modbus, use PLC4j options such as
:UDINT_LSWORD_FIRST - For other protocols, post-process with a formula
Transport (MQTT / Sparkplug)
MQTT Publish Not Working
# broker 도달 확인
MQTT_USER="${MQTT_USER:-edge}"
MQTT_PASSWORD="$(tr -d '\r\n' < /run/secrets/mqtt-password)"
mosquitto_pub -h <mqtt.server.host> -p 1883 -u "$MQTT_USER" -P "$MQTT_PASSWORD" -t /edge/point -m '{"test":1}'
Checklist:
mqtt.enable=truemqtt.server.host/port/user/passwordis correct- The broker's ACL allows publishes from this client
- Look for
MQTT connectedor reconnection logs in catalina.out
Sparkplug Topic Not Visible
| Check | How to Verify |
|---|---|
Is it sparkplug.enable=true? | Check properties + restart required |
| Is the jar in lib? | ls WebContent/WEB-INF/lib/tahu-core*.jar |
| Is it the same broker? | mqtt.server.* must match the SPB settings |
| Broker's SPB topic ACL | spBv1.0/# publish permission |
NDEATH Appears to Be Published Twice
This is normal behavior. Explicit publish on graceful shutdown + (since a will is also registered) the broker may also publish the will if it cannot detect the disconnection as a will-bypass. In that case, the host side should be implemented to process only one NDEATH with the same bdSeq.
Performance / Responsiveness
OPC Start/Stop Takes 5 Seconds
This is due to the intentional Thread.sleep in ConnectService (to guarantee collector warm-up).
- Temporary workaround: Refresh the screen to check the polling response
- Permanent fix: Apply the subsequent PR in
REFACTORING_PLAN.mdPhase A1 (Thread.sleepremoval /CountDownLatch)
Slow Initial Screen Load
There may be an additional 1–2 second delay due to opcList() N+1 queries + LastValueMap lookup distribution.
- Improvement is planned with Phase B1 (IN batch select) and B2 (single facade)
Modifying One OPC Temporarily Interrupts Others
This is because OPCUAServerManager.restart() is a full restart (Phase A2 — partial reload target).
Emergency workaround: Perform OPC modifications outside of operating hours.
Data / Cassandra
Tombstone Accumulation Warning
When deleting multiple OPCs during operation, the nodetool cfstats pe.app_tag tombstone metrics may temporarily spike.
- Not critical, as this gateway typically manages ≤ 1000 OPCs/Tags
- Time series (
TM_TAG_POINT) is the responsibility ofplantpulse-timeseries-engine, not this gateway
tag not found: <id>
Frequently occurs during PUT /api/v1/tag/{tagId} or reads.
Causes:
tag_idtypoAPP_TAG.xmlis aR03query inALLOW FILTERING, so the partition key is not specified. The tag_id must be accurate.
To verify:
cqlsh -u cassandra -p cassandra -k pe -e "SELECT tag_id FROM app_tag;"
tag write not supported for opc_type=... When Writing a Value
Write is not currently supported for protocols other than HTTP.
- Only
HTTPDriver.bind()is implemented - Write support for other protocols requires SPI extension, along with Sparkplug Phase 3 (NCMD/DCMD)
Security / Operations
/api/* Exposed Without Authentication
This is by design for on-premises networks (/api/* not included in SecurityFilter check-pattern). When exposing externally,
place mTLS / API Key / Basic auth on the front of the reverse proxy.
CSRF
CSRF applies only to the *_.do pattern. v1 mutation endpoints are excluded. Review together when exposing externally.
Log Collection Guide
Attach the following when reporting an issue to speed up analysis.
# 환경
curl -s http://localhost:8080/api/v1/edge
# OPC 상태
curl -s http://localhost:8080/api/v1/opc
# 시스템 메트릭
curl -s http://localhost:8080/api/v1/monitoring
# 최근 로그
tail -n 500 $CATALINA_HOME/logs/catalina.out
Mask passwords in app.properties before attaching.