{"record":{"id":"fe4e2183c62e57b4","repo":"v2rayA/v2rayA","slug":"listset-failed-to-clear-old-servers-of-subscripti","errorCode":null,"errorMessage":"ListSet: failed to clear old servers of subscription %d: %w","messagePattern":"ListSet: failed to clear old servers of subscription (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"service/db/listOp.go","lineNumber":79,"sourceCode":"\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\trows, _ := result.RowsAffected()\n\t\tif rows == 0 {\n\t\t\treturn fmt.Errorf(\"ListSet: subscription at index %d not found\", index)\n\t\t}\n\n\t\t// Update servers within this subscription.\n\t\t// Clean up outbound_connections first to satisfy foreign key constraint;\n\t\t// otherwise the delete fails and the insert below duplicates the list.\n\t\tif _, err := db.Exec(`\n\t\t\tDELETE FROM outbound_connections\n\t\t\tWHERE server_id IN (SELECT id FROM servers WHERE type = 'subscription_server' AND sub_id = ?)\n\t\t`, subID); err != nil {\n\t\t\treturn fmt.Errorf(\"ListSet: failed to clear outbound connections of subscription %d: %w\", index, err)\n\t\t}\n\t\tif _, err := db.Exec(\"DELETE FROM servers WHERE type = 'subscription_server' AND sub_id = ?\", subID); err != nil {\n\t\t\treturn fmt.Errorf(\"ListSet: failed to clear old servers of subscription %d: %w\", index, err)\n\t\t}\n\n\t\tservers := parsed.Get(\"servers\").Array()\n\t\tfor j, s := range servers {\n\t\t\t_, err := db.Exec(\n\t\t\t\t\"INSERT INTO servers (type, sub_id, config_json, sort) VALUES ('subscription_server', ?, ?, ?)\",\n\t\t\t\tsubID, s.Raw, j,\n\t\t\t)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"ListSet: failed to update subscription server %d/%d: %w\", index, j, err)\n\t\t\t}\n\t\t}\n\t\treturn nil\n\n\tdefault:\n\t\treturn fmt.Errorf(\"ListSet: unsupported bucket/key: %s/%s\", bucket, key)\n\t}\n}","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/v2rayA/v2rayA/blob/71e5442fc548c05680ee55eae943e6c0afe9ac51/service/db/listOp.go#L61-L97","documentation":"ListSet wraps the error from DELETE FROM servers WHERE type='subscription_server'. This delete of the subscription's old servers runs after outbound_connections are cleared (which satisfied the FK); a failure here aborts ListSet before inserting the new server rows. The %w cause carries the real DB error.","triggerScenarios":"ListSet on touch/servers or touch/subscriptions where the DELETE FROM servers for the given subID fails: locked DB, missing servers table, connection error.","commonSituations":"Concurrent writers locking the SQLite file; migration never created the servers table; DB file corruption or read-only filesystem; expired/closed connection in db.Exec.","solutions":["Read the wrapped cause to identify the driver-level failure","Verify the servers table schema (columns type, sub_id, config_json, sort) exists","Eliminate concurrent writers or use a proper transaction/locking mode","Retry after DB access is restored"],"exampleFix":"// before\nif _, err := db.Exec(\"DELETE FROM servers WHERE type = 'subscription_server' AND sub_id = ?\", subID); err != nil { ... }\n// after\n// same call, but ensure single-writer access / WAL mode: PRAGMA journal_mode=WAL; then retry ListSet","handlingStrategy":"try-catch","validationCode":"var ok int\ndb.QueryRow(\"SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='servers'\").Scan(&ok)\nif ok == 0 { return errors.New(\"servers table missing; run migrations\") }","typeGuard":null,"tryCatchPattern":"err := ListSet(\"touch\", \"servers\", val)\nif err != nil {\n    if errors.Is(err, sql.ErrConnDone) || strings.Contains(err.Error(), \"locked\") { time.Sleep(retryDelay); retry() }\n    return err\n}","preventionTips":["Enable journal_mode=WAL to reduce lock contention","Serialize writes through one goroutine or a mutex","Ping the DB before batch operations","Verify servers table columns (type, sub_id, config_json, sort) exist"],"tags":["database","sqlite","go"],"backgroundTag":"database-locked","analyzedSha":"71e5442fc548c05680ee55eae943e6c0afe9ac51","analyzedAt":"2026-09-05T20:04:37.459Z","contentChangedAt":"2026-09-05T20:04:37.459Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}