Romania XPlayZM.CSBlackDevil.COM # Zombie Plague UltimateX [ Respawn + FDL + VIP 22-12PM + POINTS] ® 32/32
Unknown ❤ RESPAWN.ZAFEST.RO | VIP FREE | FREE FOR ALL ❤ 0/32
France EMIRATES.KiNGS 亗 GAMEAREA ||͇̿P͇̿U͇̿B͇̿L͇̿I͇̿C͇̿| ✪ 32/32
Sunucu tanitimi

Fix: nVault Corrupted or Reset (AMX Mod X Vault Data Lost) #2

Merged counter-strike-boost.com merged 1 commits from tutorial/fix-nvault-corrupted-en into main
1 changed file with 105 additions and 0 deletions
+105 -0 fix-nvault-corrupted/en.md A
@@ -0,0 +1,105 @@
1 +---
2 +title: "Fix: nVault Corrupted or Reset (AMX Mod X Vault Data Lost)"
3 +excerpt: "Find out why an AMX Mod X nVault file lost its data, check the file, recover it without making things worse, and stop it happening again with backups, pruning and SQLite."
4 +category: "errors"
5 +tags: "nvault, amxx, vault, data loss, backups, sqlite"
6 +image: ""
7 +read_time: "7 min read"
8 +---
9 +<p>nVault is the AMX Mod X module behind most plugins that save XP, money or settings between maps. Each vault is one binary file of key/value pairs, usually keyed by SteamID. The format has no checksum, and the module never reports a file that failed to load: it starts with whatever it managed to read and writes that back over the file at the end of the map. That is why a damaged vault so often becomes permanent data loss, and why step one of any recovery is to copy the file before the map changes.</p>
10 +
11 +<h2>1. Where vault files live and when they are written</h2>
12 +<pre><code>cstrike/addons/amxmodx/data/vault/&lt;name&gt;.vault
13 +cstrike/addons/amxmodx/data/vault/&lt;name&gt;.journal</code></pre>
14 +<p><code>&lt;name&gt;</code> is the string the plugin passes to <code>nvault_open()</code>; search the plugin's <code>.sma</code> for it if the file name is not obvious. If you changed <code>amxx_datadir</code> in <code>configs/core.ini</code>, the folder follows it. Windows uses the same layout. The lifecycle, from the module source:</p>
15 +<ul>
16 +<li><strong>Open</strong> (normally at map start): the whole <code>.vault</code> is read into memory, any leftover <code>.journal</code> is replayed on top, then the journal is deleted and started fresh.</li>
17 +<li><strong>During the map</strong>: every set or remove is appended to the <code>.journal</code>. The <code>.vault</code> is not touched.</li>
18 +<li><strong>Close</strong> (map change, <code>nvault_close()</code>, clean shutdown): the <code>.vault</code> is truncated and rewritten in place from memory, then the journal is deleted. No temporary file, no rename.</li>
19 +</ul>
20 +<p>So a crash in the middle of a map is usually survivable: the journal is replayed at the next start, minus the last few writes still sitting in a buffer. The dangerous moment is the rewrite at map end.</p>
21 +
22 +<h2>2. Match the symptom</h2>
23 +<ul>
24 +<li><strong>Everyone's data reset at once, no error anywhere</strong>: the file header was unreadable, so the vault opened empty. The next map change writes that over the old file.</li>
25 +<li><strong>Some players kept their data, others lost it</strong>: the file is truncated. nVault loads the entries before the break and silently drops the rest.</li>
26 +<li><strong>Progress saves during a map, then reverts next map</strong>: the HLDS user cannot write the file, typically because the server was once started as root. The rewrite fails and nothing is logged.</li>
27 +<li><strong><code>Invalid vault id: -1</code></strong> with run time error 10 on <code>nvault_get</code> or <code>nvault_set</code>: <code>nvault_open()</code> failed because the vault folder or file could not be created. Any other number means the handle was closed under the plugin. See <a href="/tutorials/fix-amxx-run-time-error-10">run time error 10</a>.</li>
28 +<li><strong>Map changes take seconds and the file is many megabytes</strong>: the vault was never pruned, and every map change reads and rewrites all of it.</li>
29 +<li><strong>Crash at map change on AMX Mod X 1.8.2</strong>: 1.8.2 has two nVault crash bugs fixed in later versions, triggered by an empty key or value in the vault and by a journal it cannot write. <a href="/tutorials/upgrade-amxmodx-1-8-2-to-1-10">Upgrade</a>.</li>
30 +</ul>
31 +
32 +<h2>3. Check the file</h2>
33 +<p>A healthy vault starts with the four bytes <code>TLVn</code>. A zero-byte file is normal only for a vault created during the current map.</p>
34 +<pre><code>head -c 4 xpmod.vault; echo</code></pre>
35 +<p>For a full check, save this as <code>nvcheck.py</code> and run <code>python3 nvcheck.py xpmod.vault</code> against a copy. Any machine with Python 3 will do, including a Windows PC.</p>
36 +<pre><code>import struct, sys
37 +data = open(sys.argv[1], &quot;rb&quot;).read()
38 +if len(data) &lt; 10 or data[:4] != b&quot;TLVn&quot;:
39 + sys.exit(&quot;BAD: no nVault header (file must start with TLVn)&quot;)
40 +version, entries = struct.unpack_from(&quot;&lt;Hi&quot;, data, 4)
41 +pos, good = 10, 0
42 +while good &lt; entries and pos + 7 &lt;= len(data):
43 + stamp, klen, vlen = struct.unpack_from(&quot;&lt;iBH&quot;, data, pos)
44 + if pos + 7 + klen + vlen &gt; len(data):
45 + break
46 + pos += 7 + klen + vlen
47 + good += 1
48 +print(&quot;header says %d entries, %d readable&quot; % (entries, good))
49 +if version != 0x0200 or good != entries or pos != len(data):
50 + sys.exit(&quot;BAD: damaged after entry %d&quot; % good)
51 +print(&quot;OK&quot;)</code></pre>
52 +<p>It walks the file the way the module does. Anything but <code>OK</code> is a damaged file. <code>OK</code> with everyone reset means the keys changed, not the file: a new Reunion salt re-rolls every non-Steam SteamID.</p>
53 +
54 +<h2>4. Recover</h2>
55 +<ol>
56 +<li><strong>Copy the vault and journal now, before the map changes.</strong> Mid-map the <code>.vault</code> is not being written, so the copy is safe. At the next map change or clean shutdown, the module overwrites it with whatever it holds in memory.
57 +<pre><code>mkdir -p ~/vault-rescue
58 +cd /home/steam/hlds/cstrike/addons/amxmodx/data/vault
59 +cp -p xpmod.* ~/vault-rescue/</code></pre></li>
60 +<li><strong>Stop the server.</strong> Files restored while it runs are overwritten at the next map change.</li>
61 +<li><strong>Restore from a backup if you have one.</strong> Copy the backup's <code>.vault</code> into place and <em>delete</em> the current <code>.journal</code>. That journal holds this session's writes, including the zeroed values the plugin saved for players after the reset; replaying it onto the backup would wipe them again.</li>
62 +<li><strong>Without a backup, salvage or accept the loss.</strong> If the checker shows most entries readable (a truncated file), start the server with it: the module keeps every complete entry and writes a clean file at map end. If the header is gone, rename both files to <code>.bad</code> and let the plugin start a fresh vault. Viewers listed on the AlliedModders wiki (nVault Reader, nVault Editor) can show a readable file's contents; nothing rebuilds a missing header.</li>
63 +<li><strong>Fix the cause</strong> from the list below before starting again, then watch one full map change.</li>
64 +</ol>
65 +
66 +<h2>Common causes</h2>
67 +<ul>
68 +<li><strong>Server killed during the map-end save</strong>: <code>kill -9</code>, the out-of-memory killer, a reboot or a panel's force stop. The bigger the vault, the wider the window. Stop servers with <code>quit</code>, not by killing the process.</li>
69 +<li><strong>Disk full</strong>: the save truncates the file, fails partway, and the journal is deleted right after. This is the worst case; check <code>df -h</code> whenever a vault resets.</li>
70 +<li><strong>Wrong owner</strong>: fix it with <code>chown -R steam:steam /home/steam/hlds/cstrike/addons/amxmodx/data</code> and never start the server as root.</li>
71 +<li><strong>Two servers, one vault</strong>: several instances started from the same directory, or copies made with <code>cp -al</code> as in <a href="/tutorials/multiple-cs16-servers-one-vps">multiple servers on one VPS</a>. A vault that existed when you made the copy stays hardlinked, because nVault rewrites it in place. Each instance saves over the other's data and deletes the other's journal. Find shared files with <code>find /home/steam -path '*data/vault/*' -links +1</code>, then, with the servers stopped, give each instance its own file: <code>cp -p xpmod.vault xpmod.tmp &amp;&amp; mv xpmod.tmp xpmod.vault</code>.</li>
72 +<li><strong>Two plugins, one vault name</strong>: on one server they share a single handle and key space, so one plugin's SteamID key overwrites the other's. If one closes the vault in <code>plugin_end</code> first, the other's final saves fail with <code>Invalid vault id</code>. Give every plugin its own vault name.</li>
73 +<li><strong>Careless copies</strong>: a copy taken during a map change can catch a half-written file, and one without the <code>.journal</code> misses the current map. FTP in ASCII mode or a text editor mangles the binary file.</li>
74 +<li><strong>Oversized keys</strong>: the format stores a key's length in one byte (255 max) and a value's in two (65535 max), and the module does not check. A plugin that builds longer keys writes a record that breaks every entry after it. Fix the plugin's key format.</li>
75 +</ul>
76 +
77 +<h2>5. Prevention</h2>
78 +<p><strong>Back up the vault folder</strong> every few hours with dated archives, journals included, and keep many generations so one copy taken mid-save does not matter:</p>
79 +<pre><code>#!/bin/bash
80 +SRC=/home/steam/hlds/cstrike/addons/amxmodx/data/vault
81 +DST=/home/steam/backups/vault
82 +mkdir -p &quot;$DST&quot;
83 +tar czf &quot;$DST/vault-$(date +%F_%H%M).tar.gz&quot; -C &quot;$SRC&quot; .
84 +ls -1t &quot;$DST&quot;/vault-*.tar.gz | tail -n +57 | xargs -r rm --</code></pre>
85 +<p>Run it from the <code>steam</code> user's crontab with <code>0 */6 * * *</code>; 56 archives is two weeks. Getting copies off the box is covered in <a href="/tutorials/backup-configs-bans-stats">backing up configs, bans and stats</a>.</p>
86 +<p><strong>Prune in code</strong> if you maintain the plugin. Entries saved with <code>nvault_set()</code> carry a timestamp, so dropping players not seen for 30 days is one call after opening:</p>
87 +<pre><code>public plugin_cfg()
88 +{
89 + g_vault = nvault_open(&quot;xpmod&quot;)
90 + if (g_vault == INVALID_HANDLE)
91 + set_fail_state(&quot;Cannot open vault xpmod&quot;)
92 +
93 + nvault_prune(g_vault, 0, get_systime() - 30 * 86400)
94 +}</code></pre>
95 +<p>Entries written with <code>nvault_pset()</code> have no timestamp and are never pruned, so do not use it for per-player data. The <code>set_fail_state()</code> line turns a silent failure into a visible one.</p>
96 +<p><strong>Move structured data to SQLite.</strong> Anything with several fields per player, or that you want to sort into a top 15, belongs in a real database: see <a href="/tutorials/install-sqlite-module-amxx">the SQLite module</a>. nVault has no native that lists its keys, so migrate lazily: when a player connects and is missing from SQLite, read their old value with <code>nvault_lookup()</code>, insert it, then <code>nvault_remove()</code> the key.</p>
97 +
98 +<h2>Verification checklist</h2>
99 +<ul>
100 +<li><code>nvcheck.py</code> reports <code>OK</code> on the live vault after a map change.</li>
101 +<li>The vault and journal are owned by the HLDS user, and the <code>find ... -links +1</code> check returns nothing.</li>
102 +<li>A value changed in-game survives a map change and a full restart.</li>
103 +<li>The error log has no <code>Invalid vault id</code> lines.</li>
104 +<li>The latest backup archive exists and its <code>.vault</code> passes the checker.</li>
105 +</ul>
0 106