Skip to main content

rpfm_lib/error/
mod.rs

1//---------------------------------------------------------------------------//
2// Copyright (c) 2017-2026 Ismael Gutiérrez González. All rights reserved.
3//
4// This file is part of the Rusted PackFile Manager (RPFM) project,
5// which can be found here: https://github.com/Frodo45127/rpfm.
6//
7// This file is licensed under the MIT license, which can be found here:
8// https://github.com/Frodo45127/rpfm/blob/master/LICENSE.
9//---------------------------------------------------------------------------//
10
11//! Error types and result handling for the RPFM library.
12//!
13//! This module defines [`RLibError`], a comprehensive error type that covers all possible
14//! error conditions that can occur when working with Total War PackFiles and related files.
15//!
16//! # Error Categories
17//!
18//! The errors are organized into several categories:
19//! - **Compression/Decompression**: Errors related to file compression operations
20//! - **Encoding/Decoding**: Errors when reading or writing various file formats
21//! - **File I/O**: General file reading and writing errors
22//! - **Schema/Definition**: Errors related to missing or invalid schemas and definitions
23//! - **Game-Specific**: Errors specific to certain Total War games or features
24//! - **External Libraries**: Wrapped errors from third-party dependencies
25//!
26//! # Usage
27//!
28//! This module provides a custom [`Result`] type alias that uses [`RLibError`] as the default error type:
29//!
30//! ```ignore
31//! use rpfm_lib::error::Result;
32//!
33//! fn do_something() -> Result<String> {
34//!     // Returns Result<String, RLibError>
35//!     Ok("success".to_string())
36//! }
37//! ```
38
39use std::path::PathBuf;
40
41use thiserror::Error;
42
43use crate::files::{FileType, table::local::TableInMemory};
44
45/// Custom [`Result`] type alias that uses [`RLibError`] as the default error type.
46///
47/// This is a convenience type alias that allows functions to return `Result<T>` instead
48/// of `Result<T, RLibError>`, making function signatures cleaner throughout the codebase.
49///
50/// [`Result`]: std::result::Result
51pub type Result<T, E = RLibError> = core::result::Result<T, E>;
52
53/// Comprehensive error type for all RPFM library operations.
54///
55/// This enum covers all possible error conditions that can occur when working with
56/// Total War PackFiles and related file formats. Each variant includes descriptive
57/// error messages via the `#[error]` attribute from the `thiserror` crate.
58///
59/// # Error Display
60///
61/// All errors implement [`std::fmt::Display`] and provide user-friendly error messages.
62/// The error messages are automatically generated from the `#[error(...)]` attributes.
63#[derive(Error, Debug)]
64pub enum RLibError {
65    // Compression/Decompression Errors
66    
67    /// Error when data compression fails.
68    #[error("This file's compression failed for some reason. This means this File cannot be compressed RPFM.")]
69    DataCannotBeCompressed,
70
71    /// Error when data decompression fails.
72    #[error("This is a compressed file and the decompression failed for some reason. This means this File cannot be opened in RPFM.")]
73    DataCannotBeDecompressed,
74
75    // Manifest Errors
76
77    /// Manifest file for selected game not found.
78    #[error("The manifest for the Game Selected hasn't been found.")]
79    ManifestFileNotFound,
80
81    /// Error parsing game's manifest.txt file.
82    #[error("Error while parsing the manifest.txt file of the game selected: {0}.")]
83    ManifestFileParseError(String),
84
85    // Binary Decoding Errors
86
87    /// No more bytes available for decoding.
88    #[error("There are no more bytes to decode in the data you provided.")]
89    DecodingNotMoreBytesToDecode,
90
91    /// Invalid byte value for boolean decoding.
92    #[error("Error trying to decode \"{0}\" as boolean: invalid value.")]
93    DecodingBoolError(u8),
94
95    /// No bytes remaining for number decoding.
96    #[error("Error trying to decode a byte as a number: No bytes left to decode.")]
97    DecodingNoBytesLeftError,
98
99    /// Insufficient bytes for type decoding.
100    #[error("Error trying to decode an {0} value: Required bytes: {1}. Provided bytes: {2:?}.")]
101    DecodingNotEnoughBytesToDecodeForType(String, usize, Option<usize>),
102
103    /// Wrapper for integer parsing errors.
104    #[error(transparent)]
105    DecodeIntError(#[from] std::num::ParseIntError),
106
107    /// Wrapper for float parsing errors.
108    #[error(transparent)]
109    DecodeFloatError(#[from] std::num::ParseFloatError),
110
111    /// Wrapper for UTF-8 string conversion errors.
112    #[error(transparent)]
113    DecodeUTF8Error(#[from] std::string::FromUtf8Error),
114
115    /// Wrapper for UTF-8 string slice validation errors.
116    #[error(transparent)]
117    DecodeUTF8StrError(#[from] std::str::Utf8Error),
118
119    /// Wrapper for UTF-16 string conversion errors.
120    #[error(transparent)]
121    DecodeUTF16Error(#[from] std::string::FromUtf16Error),
122
123    /// UTF-16 string has odd byte count.
124    #[error("Error trying to decode an UTF-16 String. We expected an even amount of bytes, but instead we have {0} bytes.")]
125    DecodeUTF16UnevenInputError(usize),
126
127    /// ISO-8859-1 to UTF-8 conversion failed.
128    #[error("Error trying to convert an ISO8859-1 String to an UTF-8 String: {0}.")]
129    DecodeUTF8FromISO8859Error(String),
130
131    /// String size cannot be determined.
132    #[error("Error trying to decode an {0}: Not enough bytes to get his size.")]
133    DecodingStringSizeError(String),
134
135    /// Optional string missing boolean prefix.
136    #[error("Error trying to decode an {0}: The first byte is not a boolean.")]
137    DecodingOptionalStringBoolError(String),
138
139    /// Null-terminated string missing terminator.
140    #[error("Error trying to read an 00-Terminated String: No byte 00 found.")]
141    DecodingString0TeminatedNo0Error,
142
143    /// Padded string exceeds maximum length.
144    #[error("Error trying to encode an {0}: \"{1}\" has a length of {2} chars, but his length should be less or equal than {3}.")]
145    EncodingPaddedStringError(String, String, usize, usize),
146
147    // Game Installation Errors
148
149    /// Game install type not supported.
150    #[error("The game with the key \"{0}\" is not supported for the install type \"{1}\".")]
151    GameInstallTypeNotSupported(String, String),
152
153    /// Launch command not supported for game install type.
154    #[error("Launch commands for game \"{0}\", install type \"{1}\" are not currently supported.")]
155    GameInstallLaunchNotSupported(String, String),
156
157    /// Invalid boolean value string.
158    #[error("Error trying to convert the following value to a bool: {0}.")]
159    ParseBoolError(String),
160
161    /// File or folder cannot be read.
162    #[error("Error while trying to read the following file/folder: {0}. \
163        This means that path may not be readable (permissions? other programs locking access to it?) or may not exists at all.")]
164    ReadFileFolderError(String),
165
166    // PackFile Structure Errors
167
168    /// PackFile header corrupted or unsupported.
169    #[error("The header of the Pack is incomplete, unsupported or damaged.")]
170    PackHeaderNotComplete,
171
172    /// PackFile subheader missing or corrupted.
173    #[error("The subheader of the Pack is incomplete, unsupported or damaged.")]
174    PackSubHeaderMissing,
175
176    /// PackFile indexes corrupted or incomplete.
177    #[error("The indexes of the Pack are incomplete, unsupported or damaged")]
178    PackIndexesNotComplete,
179
180    /// Unknown PFH file type.
181    #[error("Unknown PFH File Type: {0}")]
182    UnknownPFHFileType(String),
183
184    /// Unknown PFH version.
185    #[error("Unknown PFH Version: {0}")]
186    UnknownPFHVersion(String),
187
188    // File Format Errors
189
190    /// Unknown ESF signature string.
191    #[error("Unknown ESF Signature: {0}")]
192    UnknownESFSignature(String),
193
194    /// Unknown ESF signature bytes.
195    #[error("Unknown ESF Signature: {0:#X} {1:#X}")]
196    UnknownESFSignatureBytes(u8, u8),
197
198    /// Unknown Empire File line type.
199    #[error("Unknown EF Line Type: {0}")]
200    UnknownEFLineType(String),
201
202    /// Unknown pipe type.
203    #[error("Unknown Pipe Type: {0}")]
204    UnknownPipeType(String),
205
206    /// CS2 migration not supported for this game.
207    #[error("Migration to this game is not yet supported for cs2.parsed files.")]
208    GameDoesntSupportCs2Migration,
209
210    /// Text file encoding unsupported or not a text file.
211    #[error("This is either not a Text File, or a Text File using an unsupported encoding")]
212    DecodingTextUnsupportedEncodingOrNotATextFile,
213
214    /// Unknown anim table version.
215    #[error("This file has an unknown/unsupported version: {0}.")]
216    DecodingAnimsTableUnknownVersion(i32),
217
218    /// Unknown/unresearched Group Formations block type.
219    #[error("Unknown/unsupported Group Formations block type: {0}.")]
220    DecodingGroupFormationsUnknownBlockType(u32),
221
222    /// File is not CA_VP8 or IVF format.
223    #[error("This file is neither a CA_VP8 nor an IVF file.")]
224    DecodingCAVP8UnsupportedFormat,
225
226    /// CA_VP8 frame size invalid.
227    #[error("Incorrect/Unknown Frame size.")]
228    DecodingCAVP8IncorrectOrUnknownFrameSize,
229
230    // ESF Errors
231
232    /// ESF signature not supported.
233    #[error("Unsupported signature: {0:#X} {1:#X}.")]
234    DecodingESFUnsupportedSignature(u8, u8),
235
236    /// ESF data type not supported.
237    #[error("Unsupported data type: {0}.")]
238    DecodingESFUnsupportedDataType(u8),
239
240    /// ESF record name not in string table.
241    #[error("Record name not found: {0}.")]
242    DecodingESFRecordNameNotFound(u16),
243
244    /// ESF string not in string table.
245    #[error("String not found: {0}.")]
246    DecodingESFStringNotFound(u32),
247
248    /// ESF encoding signature not supported.
249    #[error("Unsupported signature: {0}.")]
250    EncodingESFUnsupportedSignature(String),
251
252    // Campaign Map Data Errors
253
254    /// Trade routes (PTD) file signature not supported.
255    #[error("Unsupported trade routes signature: {0:#X?}.")]
256    DecodingPTDUnsupportedSignature(Vec<u8>),
257
258    /// Trade routes (PTD) file version not supported.
259    #[error("Unsupported trade routes version: {0}.")]
260    DecodingPTDUnsupportedVersion(u32),
261
262    /// Campaign map data missing or malformed.
263    #[error("Invalid campaign map data: {0}")]
264    CampaignMapDataError(String),
265
266    /// A table needed to build a startpos is missing.
267    #[error("Missing table needed to build the startpos: {0}.")]
268    StartposMissingTable(String),
269
270    /// A column needed to build a startpos is missing from its table.
271    #[error("Missing column {1} in table {0}, needed to build the startpos.")]
272    StartposMissingColumn(String, String),
273
274    /// A startpos layout is missing something, or a value doesn't fit it.
275    #[error("Startpos layout error: {0}")]
276    StartposLayoutError(String),
277
278    /// A table value needed to build a startpos has the wrong type or is out of range.
279    #[error("Invalid value in column {1} of table {0}, needed to build the startpos: {2}")]
280    StartposInvalidValue(String, String, String),
281
282    /// A startpos lacks something needed to extract its tables.
283    #[error("The tables of the startpos can't be extracted: {0}")]
284    StartposExtractionError(String),
285
286    /// A mission script needed to build a startpos (like `victory_objectives.txt`) is malformed or uses something
287    /// unsupported.
288    #[error("Invalid mission script: {0}")]
289    StartposScriptError(String),
290
291    // Font File Errors
292
293    /// Font file signature not supported.
294    #[error("Unsupported signature: {0:#X?}.")]
295    DecodingFontUnsupportedSignature(Vec<u8>),
296
297    // Asset Variation DB Errors
298
299    /// Asset variation DB in XML form that can't be read.
300    #[error("Invalid asset variation DB XML: {0}")]
301    DecodingAssetVariationDbXml(String),
302
303    /// Edit of an asset variation DB that would leave it wrong for the game.
304    #[error("{0}")]
305    AssetVariationDbEditRefused(String),
306
307    // Tile Database Errors
308
309    /// Tile database source in the Assembly Kit that can't be read.
310    #[error("Invalid tile database XML: {0}")]
311    DecodingTileDatabaseXml(String),
312
313    // Fxc Errors
314
315    /// Fxc (compiled shader container) signature not supported.
316    #[error("Unsupported fxc signature: {0:#X}.")]
317    DecodingFxcUnsupportedSignature(u32),
318
319    /// Fxc version not supported for decoding.
320    #[error("Unsupported fxc version: {0}.")]
321    DecodingFxcUnsupportedVersion(u32),
322
323    /// Fxc version not supported for encoding.
324    #[error("Unsupported fxc version: {0}.")]
325    EncodingFxcUnsupportedVersion(u32),
326
327    /// Fxc shader is not a DXBC blob, or its size doesn't match the rest of the file.
328    #[error("The shader of this fxc file is not a valid DXBC blob.")]
329    DecodingFxcInvalidShader,
330
331    // FastBin Errors
332
333    /// FastBin signature not supported.
334    #[error("Unsupported signature: {0:#X?}.")]
335    DecodingFastBinUnsupportedSignature(Vec<u8>),
336
337    /// FastBin version not supported for decoding.
338    #[error("Unsupported version {1} for type {0}.")]
339    DecodingFastBinUnsupportedVersion(String, u16),
340
341    /// FastBin version not supported for encoding.
342    #[error("Unsupported version {1} for type {0}.")]
343    EncodingFastBinUnsupportedVersion(String, u16),
344
345    /// FastBin section with data in a version where its layout is unknown.
346    #[error("The {0} section has data, but its layout in this version is unknown.")]
347    DecodingFastBinUnknownSection(String),
348
349    // RigidModel Errors
350
351    /// RigidModel signature not supported.
352    #[error("Unsupported signature: {0:#X?}.")]
353    DecodingRigidModelUnsupportedSignature(Vec<u8>),
354
355    /// RigidModel version not supported.
356    #[error("Unknown rigid model version: {0}")]
357    DecodingRigidModelUnsupportedVersion(u32),
358
359    /// RigidModel material type not supported.
360    #[error("Unsupported material type: {0}.")]
361    DecodingRigidModelUnsupportedMaterialType(u16),
362
363    /// RigidModel texture type unknown.
364    #[error("Unsupported texture type: {0}.")]
365    DecodingRigidModelUnknownTextureType(i32),
366
367    /// RigidModel vertex format unknown.
368    #[error("Unsupported vertex format: {0}.")]
369    DecodingRigidModelUnknownVertexFormat(u16),
370
371    /// RigidModel vertex format incompatible with material.
372    #[error("Unsupported vertex format {0} for material {1}.")]
373    DecodingRigidModelUnsupportedVertexFormatForMaterial(u16, u16),
374
375    /// RigidModel rope with a link count that doesn't match its nodes.
376    #[error("A rope with {0} nodes needs one link fewer, but it has {1}.")]
377    EncodingRigidModelRopeLinkCountMismatch(usize, usize),
378
379    /// Group Formations unknown enum value.
380    #[error("Unknown group formations {0} value: {1}.")]
381    DecodingGroupFormationsUnknownEnumValue(String, u32),
382
383    /// Group Formations block not found in its formation.
384    #[error("There is no block with id {0} in this formation.")]
385    GroupFormationsBlockNotFound(u32),
386
387    /// Group Formations operation that only applies to containers, used on a span.
388    #[error("Block {0} is a span, and this operation only works with containers.")]
389    GroupFormationsBlockIsNotAContainer(u32),
390
391    /// Group Formations operation that only applies to spans, used on a container.
392    #[error("Block {0} is a container, and this operation only works with spans.")]
393    GroupFormationsBlockIsNotASpan(u32),
394
395    /// Group Formations block without a position, due to broken references.
396    #[error("Block {0} can't be positioned, because it depends on missing blocks or on itself.")]
397    GroupFormationsBlockNotPlaceable(u32),
398
399    /// Group Formations reference that would make blocks depend on each other in a loop.
400    #[error("Block {0} can't depend on block {1}, because block {1} already depends on block {0}.")]
401    GroupFormationsCyclicReference(u32, u32),
402
403    /// Group Formations value of a version not used by the game being encoded.
404    #[error("A group formations {0} value doesn't match the version used by the selected game.")]
405    EncodingGroupFormationsMismatchedVersion(String),
406
407    // Table Decoding Errors
408
409    /// Combined colour field decoding failed.
410    #[error("Error decoding combined colour.")]
411    DecodingTableCombinedColour,
412
413    // SoundBank Errors
414
415    /// SoundBank BKHD header section missing.
416    #[error("Header section not found. This shouldn't happen.")]
417    SoundBankBKHDNotFound,
418
419    /// SoundBank section type not supported.
420    #[error("Unsupported section {0} found in SoundBank.")]
421    SoundBankUnsupportedSectionFound(String),
422
423    /// SoundBank object version not supported.
424    #[error("Unsupported version {0} for object of type {1} found in SoundBank.")]
425    SoundBankUnsupportedVersionFound(u32, String),
426
427    /// SoundBank language ID not supported.
428    #[error("Unsupported language id {0} found in SoundBank.")]
429    SoundBankUnsupportedLanguageFound(u32),
430
431    /// SoundBank object type not supported.
432    #[error("Unsupported object type {0} found in SoundBank.")]
433    SoundBankUnsupportedObjectTypeFound(u8),
434
435    // Table Field Errors
436
437    /// Table field decoding failed.
438    #[error("Error trying to decode the Row {0}, Cell {1} as a {2} value: either the value is not a {2}, or there are insufficient bytes left to decode it as a {2} value.")]
439    DecodingTableFieldError(u32, u32, String),
440
441    /// Table sequence field index out of bounds.
442    #[error("Error trying to get the data for a {3} on Row {0}, Cell {1}: invalid ending index {2}.")]
443    DecodingTableFieldSequenceIndexError(u32, u32, usize, String),
444
445    /// Table sequence field data invalid.
446    #[error("Error trying to get the data for a {3} on Row {0}, Cell {1}: {2}.")]
447    DecodingTableFieldSequenceDataError(u32, u32, String, String),
448
449    /// Table decoding incomplete with partial data.
450    #[error("Error trying to decode a table: {0}. The incomplete table is: {1:#?}.")]
451    DecodingTableIncomplete(String, Box<TableInMemory>),
452
453    // Extra Data Errors
454
455    /// Required extra decoding data missing.
456    #[error("Missing extra data required to decode the file. This means the programmer messed up the code while that tries to decode files.")]
457    DecodingMissingExtraData,
458
459    /// Extra data field missing or invalid.
460    #[error("Missing or invalid extra data provided: \"{0}\"")]
461    DecodingMissingExtraDataField(String),
462
463    /// File decoding not supported for selected game.
464    #[error("Decoding of this file is unsupported for game: \"{0}\"")]
465    DecodingUnsupportedGameSelected(String),
466
467    // Table Encoding Errors
468
469    /// Table row field count mismatch.
470    #[error("Error while trying to save a row from a table: We expected a row with \"{0}\" fields, but we got a row with \"{1}\" fields instead. Rows must match Definition::fields_processed() (bitwise/enum/colour groups collapsed), not the raw Definition::fields() layout.")]
471    TableRowWrongFieldCount(usize, usize),
472
473    /// Table field type mismatch.
474    #[error("Error while trying to save a row from a table: We expected a field of type \"{0}\", but we got a field of type \"{1}\".")]
475    EncodingTableWrongFieldType(String, String),
476
477    // Schema/Definition Errors
478
479    /// Table definition missing and file empty.
480    #[error("There are no definitions for this specific version of the table in the Schema and the table is empty. This means this table cannot be open nor decoded.")]
481    DecodingDBNoDefinitionsFoundAndEmptyFile,
482
483    /// Table definition missing from schema.
484    #[error("There are no definitions for this specific version of the table in the Schema.")]
485    DecodingDBNoDefinitionsFound,
486
487    /// File not a valid DB table.
488    #[error("This is either not a DB Table, or it's a DB Table but it's corrupted.")]
489    DecodingDBNotADBTable,
490
491    /// File not a valid Loc table.
492    #[error("This is either not a Loc Table, or it's a Loc Table but it's corrupted.")]
493    DecodingLocNotALocTable,
494
495    /// File not a valid Matched Combat table.
496    #[error("This is either not a Matched Combat Table, or it's a Matched Combat Table but it's corrupted.")]
497    DecodingMatchedCombatNotAMatchedCombatTable,
498
499    /// File not a valid Unit Variant.
500    #[error("This is either not an Unit Variant, or it's an Unit Variant but it's corrupted.")]
501    DecodingUnitVariantNotAUnitVariant,
502
503    /// File size mismatch with expected size.
504    #[error("This file's reported size is '{0}' bytes, but we expected it to be '{1}' bytes. This means that the definition of the table is incorrect (only on tables, it's usually this), the decoding logic in RPFM is broken for this file, or this file is corrupted.")]
505    DecodingMismatchSizeError(usize, usize),
506
507    // Version Errors
508
509    /// Portrait Settings version not supported.
510    #[error("This file's version ({0}) is not yet supported.")]
511    DecodingPortraitSettingUnsupportedVersion(usize),
512
513    /// Generic unsupported version error.
514    #[error("This file's version ({0}) is not yet supported.")]
515    DecodingUnsupportedVersion(usize),
516
517    /// Anim Fragment version not supported.
518    #[error("This file's version ({0}) is not yet supported.")]
519    DecodingAnimFragmentUnsupportedVersion(usize),
520
521    /// Matched Combat version not supported.
522    #[error("This file's version ({0}) is not yet supported.")]
523    DecodingMatchedCombatUnsupportedVersion(usize),
524
525    // File Type Errors
526
527    /// Decoded data type doesn't match expected file type.
528    #[error("This file is expected to be of {0} type, but the data provided is of {1} type. If you see this, 99% sure it is a bug.")]
529    DecodedDataDoesNotMatchFileType(FileType, FileType),
530
531    /// SoundPacked decoding not supported for game.
532    #[error("Decoding of SoundPacked files is not supported for this game: {0}.")]
533    DecodingSoundPackedUnsupportedGame(String),
534
535    /// SoundPacked encoding not supported for game.
536    #[error("Encoding of SoundPacked files is not supported for this game: {0}.")]
537    EncodingSoundPackedUnsupportedGame(String),
538
539    /// Required extra encoding data missing.
540    #[error("Missing extra data required to encode the file. This means the programmer messed up the code while that tries to decode files.")]
541    EncodingMissingExtraData,
542
543    /// Invalid state participant value.
544    #[error("Invalid state participant value: {0}")]
545    InvalidStateParticipantValue(u32),
546
547    // Git Repository Errors
548
549    /// Git repository download or update failed.
550    #[error("There was an error while downloading/updating the following git repository: {0}.")]
551    GitErrorDownloadFromRepo(String),
552
553    /// No updates available for git repository.
554    #[error("No updates available for the following git repository: {0}.")]
555    GitErrorNoUpdatesAvailable(String),
556
557    // GitHub Errors
558
559    /// GitHub rejected the token, so the user has to sign in again.
560    #[error("GitHub rejected the sign-in. Please, sign in again.")]
561    GitHubUnauthorized,
562
563    /// A GitHub request failed. Contains the endpoint, the HTTP status and GitHub's message.
564    #[error("GitHub request to {0} failed ({1}): {2}")]
565    GitHubApi(String, u16, String),
566
567    /// A GitHub repository doesn't exist, or the user can't see it.
568    #[error("The GitHub repository {0} doesn't exist, or you don't have access to it.")]
569    GitHubRepositoryNotFound(String),
570
571    /// A newly created fork didn't become usable in time.
572    #[error("GitHub is taking too long to create your fork of {0}. Please, try again in a few minutes.")]
573    GitHubForkNotReady(String),
574
575    // Lazy Loading Errors
576
577    /// File data changed on disk during lazy loading.
578    #[error("The file's data for file ({0}) has been altered on disk by another program since the last time it was accessed by us. If you see this, it means you're using lazy-loading and another program has altered the data on disk before this program loaded it to memory.
579
580        Basically, this means your Pack got partially corrupted.
581
582        If you see this message in a program that's not RPFM,... ask its author what to do.
583
584        If you see this message in RPFM, your original Pack on disk should still be safe, and RPFM can recover part of the files inside the open PackFile: DB tables, Locs and any PackedFile open before this message appeared. To do that, go to 'Special Stuff' and hit 'Rescue PackFile', then choose a folder to save the clean Pack.
585
586        That will create a Pack with only the files that were confirmed as non-corrupted, so at least you can recover their data.
587
588        And some final words: if you intentionally opened the same Pack in two instances of RPFM and tried to save on both, that was the cause of this. No, it's not a bug in RPFM. No, I can't magically fix it. It's how lazy-loading data from disk works. If you don't like it, you can disable lazy-loading in the settings. You'll be resistant to Pack corruption, but RPFM will use a ton more RAM. So... choose your poison.
589
590        Note: if this message appeared while adding files from a Pack, you're save. Just close the 'Add From PackFile' tab and open it again.")]
591    FileSourceChanged(String),
592
593    // Size/Limit Errors
594
595    /// File too large for container.
596    #[error("At least one of the files (`{3}`) on this {0} is too big for it. The maximum supported size for files is {1}, but your file has {2} bytes.")]
597    DataTooBigForContainer(String, u64, usize, String),
598
599    // File Operation Errors
600
601    /// File not found in pack.
602    #[error("The following file hasn't been found: {0}.")]
603    FileNotFound(String),
604
605    /// File not yet decoded.
606    #[error("The following file hasn't yet been decoded: {0}.")]
607    FileNotDecoded(String),
608
609    /// File not yet cached.
610    #[error("The following file hasn't yet been cached: {0}.")]
611    FileNotCached(String),
612
613    /// Reserved file operation blocked.
614    #[error("Operation not allowed: reserved file detected.")]
615    ReservedFiles,
616
617    /// Empty destination path.
618    #[error("Operation not allowed: destiny is blank for your file.")]
619    EmptyDestiny,
620
621    /// No packs provided to operation.
622    #[error("No Packs provided.")]
623    NoPacksProvided,
624
625    /// Live export has no files to export.
626    #[error("No files to export.")]
627    LiveExportNoFilesToExport,
628
629    // Build/Update Errors
630
631    /// Startpos build error.
632    #[error("{0}")]
633    BuildStartposError(String),
634
635    /// Animation IDs update error.
636    #[error("{0}")]
637    UpdateAnimIdsError(String),
638
639    // SQLite Errors
640
641    /// SQLite connection pool not initialized.
642    #[error("The SQLite connection pool hasn't been initialized yet.")]
643    MissingSQLitePool,
644
645    /// Path missing filename component.
646    #[error("The path {0} doesn't have an identifiable filename.")]
647    PathMissingFileName(String),
648
649    // Dependencies Cache Errors
650
651    /// Dependencies cache not generated or outdated.
652    #[error("The dependencies cache has not been generated or it's outdated and need regenerating.")]
653    DependenciesCacheNotGeneratedorOutOfDate,
654
655    /// File not found in dependencies cache.
656    #[error("The file with the path {0} hasn't been found in the dependencies cache.")]
657    DependenciesCacheFileNotFound(String),
658
659    // Definition Update Errors
660
661    /// Table already has latest definition.
662    #[error("This table already has the newer definition available.")]
663    NoDefinitionUpdateAvailable,
664
665    /// Table not found in game files for comparison.
666    #[error("This table cannot be found in the Game Files, so it cannot be automatically updated (yet).")]
667    NoTableInGameFilesToCompare,
668
669    // Assembly Kit Errors
670
671    /// Assembly Kit version not supported.
672    #[error("Operations over the Assembly Kit of version {0} are not currently supported.")]
673    AssemblyKitUnsupportedVersion(i16),
674
675    /// Assembly Kit folder not found or readable.
676    #[error("The Assembly Kit Folder could not be read. You may need to install the Assembly Kit.")]
677    AssemblyKitNotFound,
678
679    /// Table not found in Assembly Kit.
680    #[error("The table {0} was not found in the Assembly Kit.")]
681    AssemblyKitTableNotFound(String),
682
683    /// Assembly Kit table blacklisted.
684    #[error("One of the Assembly Kit Tables you tried to decode has been blacklisted due to issues.")]
685    AssemblyKitTableTableIgnored,
686
687    /// Localisable fields file not found.
688    #[error("The `Localisable Fields` file hasn't been found.")]
689    AssemblyKitLocalisableFieldsNotFound,
690
691    /// Relationships file not found.
692    #[error("The relationships file hasn't been found.")]
693    AssemblyKitExtraRelationshipsNotFound,
694
695    /// Raw table import missing definition.
696    #[error("The raw table you tried to import is missing a definition.")]
697    RawTableMissingDefinition,
698
699    // TSV Import Errors
700
701    /// TSV import row/field error.
702    #[error("This TSV file has an error in the row {0}, field {1} (both starting at 0). Please, check it and make sure the value in that field is a valid value for that column.")]
703    ImportTSVIncorrectRow(usize, usize),
704
705    /// TSV file incompatible or wrong type.
706    #[error("This TSV file either belongs to another table, to a localization File, it's broken or it's incompatible with RPFM.")]
707    ImportTSVWrongTypeTable,
708
709    /// TSV file has invalid version.
710    #[error("This TSV file has an invalid version value at line 1.")]
711    ImportTSVInvalidVersion,
712
713    /// TSV file missing or invalid path.
714    #[error("This TSV file has an invalid or missing file path value at line 1.")]
715    ImportTSVInvalidOrMissingPath,
716
717    /// TSV export requested for a file type that isn't DB or Loc.
718    #[error("TSV export is only supported for DB and Loc files.")]
719    ExportTSVUnsupportedFileType,
720
721    // File Merge Errors
722
723    /// Merge requires multiple files.
724    #[error("You need to pass more than one file to merge.")]
725    RFileMergeOnlyOneFileProvided,
726
727    /// Cannot merge files of different types.
728    #[error("Merging files of different types is not supported.")]
729    RFileMergeDifferentTypes,
730
731    /// Cannot merge tables with different names.
732    #[error("Merging tables with different table names is not supported.")]
733    RFileMergeTablesDifferentNames,
734
735    /// Table merge requires at least two tables.
736    #[error("Merging tables needs at least two tables.")]
737    RFileMergeTablesNotEnoughTablesProvided,
738
739    /// File type doesn't support merging.
740    #[error("Merging files of type {0} is not supported.")]
741    RFileMergeNotSupportedForType(String),
742
743    // Group Formation Errors
744
745    /// Group formation block type unknown.
746    #[error("Block Type {0} is not supported.")]
747    GroupFormationUnknownBlockType(u32),
748
749    // Patch Errors
750
751    /// Cannot patch empty pack.
752    #[error("This Pack is empty, so we can't patch it.")]
753    PatchSiegeAIEmptyPack,
754
755    /// No patchable files in pack.
756    #[error("There are not files in this Pack that could be patched/deleted.")]
757    PatchSiegeAINoPatchableFiles,
758
759    /// No schema provided when required.
760    #[error("No Schema provided.")]
761    SchemaNotProvided,
762
763    // IVF Errors
764
765    /// Invalid subtraction during IVF processing.
766    #[error("Invalid subtraction when processing an IVF file. This means the something went wrong when saving the IVF file.")]
767    IVFInvalidSubstraction,
768
769    // Steam Workshop Errors
770
771    /// Game doesn't support Steam Workshop.
772    #[error("The game {0} doesn't support the Steam Workshop.")]
773    GameDoesntSupportWorkshop(String),
774
775    /// SteamID not recognized as Total War game.
776    #[error("The SteamID {0} doesn't belong to any known Total War game.")]
777    SteamIDDoesntBelongToKnownGame(u64),
778
779    // Global Search/Replace Errors
780
781    /// Global replace requires same byte length without regex.
782    #[error("You're trying to perform a Global Replace on a type that doesn't support Regex replacement and requires that both, pattern and replacement have the exact same byte length. To avoid breaking files this program doesn't allow you to do that. Either make sure both strings have the exact same byte length, don't use regex, or use a hexadecimal editor.")]
783    GlobalSearchReplaceRequiresSameLengthAndNotRegex,
784
785    /// IO error with associated path.
786    #[error("Error in path: {1}. {0}")]
787    IOErrorPath(Box<Self>, PathBuf),
788
789    // Translation Errors
790
791    /// No translation found.
792    #[error("No translation could be found.")]
793    TranslatorCouldNotLoadTranslation,
794
795    // Lua Test Errors
796
797    /// The test file of a Lua test run can't be loaded.
798    #[error("The Lua test file could not be loaded: {0}")]
799    LuaTestFileError(String),
800
801    /// The game's scripts are not available to run Lua tests.
802    #[error("The game's scripts could not be found. Make sure the dependencies cache of the game is generated and up to date.")]
803    LuaTestGameScriptsNotFound,
804
805    /// The Lua runtime used to run tests failed.
806    #[error("The Lua runtime failed: {0}")]
807    LuaRuntimeError(String),
808
809    // GameInfo Errors
810
811    /// GameInfo missing from pack-reading function.
812    #[error("GameInfo has not been provided to the pack-reading function when reading the pack.")]
813    GameInfoMissingFromDecodingFunction,
814
815    /// GameInfo missing from pack-saving function.
816    #[error("GameInfo has not been provided to the pack-saving function when saving the pack.")]
817    GameInfoMissingFromEncodingFunction,
818
819    // External Library Error Wrappers
820
821    /// Wrapper for [`std::io::Error`] errors.
822    #[error(transparent)]
823    IOError(#[from] std::io::Error),
824
825    /// Wrapper for [`git2::Error`] errors.
826    #[cfg(feature = "integration_git")]
827    #[error(transparent)]
828    GitError(#[from] git2::Error),
829
830    /// Wrapper for [`reqwest::Error`] errors.
831    #[cfg(feature = "integration_github")]
832    #[error(transparent)]
833    ReqwestError(#[from] reqwest::Error),
834
835    /// Wrapper for [`ron::Error`] errors.
836    #[error(transparent)]
837    RonError(#[from] ron::Error),
838
839    /// Wrapper for [`ron::error::SpannedError`] errors.
840    #[error(transparent)]
841    RonSpannedError(#[from] ron::error::SpannedError),
842
843    /// Wrapper for [`csv::Error`] errors.
844    #[error(transparent)]
845    CSVError(#[from] csv::Error),
846
847    /// Wrapper for [`serde_json::Error`] errors.
848    #[error(transparent)]
849    JsonError(#[from] serde_json::Error),
850
851    /// Wrapper for [`std::array::TryFromSliceError`] errors.
852    #[error(transparent)]
853    TryFromSliceError(#[from] std::array::TryFromSliceError),
854
855    /// Wrapper for [`std::time::SystemTimeError`] errors.
856    #[error(transparent)]
857    SystemTimeError(#[from] std::time::SystemTimeError),
858
859    /// Wrapper for [`std::path::StripPrefixError`] errors.
860    #[error(transparent)]
861    StripPrefixError(#[from] std::path::StripPrefixError),
862
863    /// Wrapper for [`r2d2::Error`] errors.
864    #[cfg(feature = "integration_sqlite")]
865    #[error(transparent)]
866    R2D2Error(#[from] r2d2::Error),
867
868    /// Wrapper for [`rusqlite::Error`] errors.
869    #[cfg(feature = "integration_sqlite")]
870    #[error(transparent)]
871    RusqliteError(#[from] rusqlite::Error),
872
873    /// Wrapper for [`toml::ser::Error`] errors.
874    #[error(transparent)]
875    TomlError(#[from] toml::ser::Error),
876
877    /// Wrapper for [`bitcode::Error`] errors.
878    #[cfg(feature = "support_error_bitcode")]
879    #[error(transparent)]
880    BitcodeError(#[from] bitcode::Error),
881
882    /// Wrapper for [`serde_xml_rs::Error`] errors.
883    #[error(transparent)]
884    XmlRsError(#[from] serde_xml_rs::Error),
885
886    /// Wrapper for [`log::SetLoggerError`] errors.
887    #[error(transparent)]
888    LogError(#[from] log::SetLoggerError),
889
890    /// Wrapper for [`lz4_flex::frame::Error`] errors.
891    #[error(transparent)]
892    Lz4Error(#[from] lz4_flex::frame::Error),
893
894    /// Wrapper for [`lz4_flex::block::DecompressError`] errors.
895    #[error(transparent)]
896    Lz4BlockError(#[from] lz4_flex::block::DecompressError),
897
898    /// Wrapper for [`lzma_rs::error::Error`] errors.
899    #[error(transparent)]
900    LzmaError(#[from] lzma_rs::error::Error),
901
902    /// Wrapper for [`image::ImageError`] errors.
903    #[error(transparent)]
904    ImageError(#[from] image::ImageError),
905
906    /// Wrapper for [`dds::DecodingError`] errors.
907    #[error(transparent)]
908    DDSDecError(#[from] dds::DecodingError),
909
910    /// Wrapper for [`dds::EncodingError`] errors.
911    #[error(transparent)]
912    DDSEncError(#[from] dds::EncodingError),
913
914    /// DDS colour format not supported.
915    #[error("Unsupported colour format for DDS files.")]
916    DecodingDDSColourFormatUnsupported,
917}