Thank you for spotting this problem. You should find that modules having versions which don’t match their releases are rejected now.
Given what has been stated about not re-uploading files already in the old library (in order to avoid duplicating files), when splitting projects should we message, to the administrator, lists of files to be moved? If so, I presume the new project pages should be made so that the files can be dropped into them.
Also, at the present time at least the administrator should be messaged about any extraneous material on a project page that needs deletion, if the “owner” can’t do it; correct?
Great. A few questions
-
Is the match supposed to be exact? E.g., will module version
1.2.3-alpha
match only release1.2.3-alpha
, or will it also match1.2.3
? It seems that the match must be exact. If so, is that really what you want? I mean, you could have a future release, say1.2.3
to which you upload a pre-release1.2.3-alpha
, or a release1.2.3
to which you upload a specific build1.2.3+french
. -
Should module extensions (
.vext
) not also be checked against the release? -
What about saves (
.vsav
), logs (.vlog
), and older extensions (.vmdx
)? Shouldn’t they be checked too? -
It seems that checking the release number depends on the uploaded file name ending in either
.vmod
or.vext
. Shouldn’t the check be done based on the content (mime-type) of the file? E.g., similar to what you have inimage.rs
for images:- Check if file is mime-type
application/zip
- Check if archive contains
moduledata
- If so, investigate
data/version
in the XML
- If so, investigate
- Check if archive contains
Currently, a user could upload a module which file name ends in say
.vmd
and thereby by-pass the release check. - Check if file is mime-type
Again, with the caveat that I’m not too familiar with Rust
pub fn is_magic_zip(mime: &Mime) -> bool {
mime == &mime::APPLICATION && mime.sub_type() == "zip";
}
fn is_zip_archive<P: AsRef<Path>>(
path: P,
buf: &[u8]
) -> bool {
match infer::get(buf) {
Some(info) =>
info.mime_type().parse::<Mime>()
.is_ok_and(|mime| is_magic_zip(&mime)),
None => false
}
}
fn moduledata_in_zip<P: AsRef<Path>>(
path: P) -> Result<String, Error>
{
let zipfile = File::open(zippath)?;
let mut archive = ZipArchive::new(zipfile)?;
// check for moduledata in archive
let mut file = archive.by_name("moduledata");
if ! file {
return Ok("");
}
let mut data = String::new();
file.read_to_string(&mut data)?;
Ok(data)
}
// Return empty string if not VASSAL file (zip archive and contains moduledata)
// otherwise, the version number set in moduledata
fn check_for_vassal_file(<P: AsRef<Path>>(
path: P,
buf: &[u8]
) -> Result<String,Error> {
if ! is_zip_archive(path,buf) {
return "";
}
let md = moduledata_in_zip(path)?;
if md == "" {
return "";
}
let package = sxd_document::parser::parse(md)?;
let document = package.as_document();
let value = sxd_xpath::evaluate_xpath(&document, "/data/version")?;
Ok(value.string())
}
and then in line 326 of prod_core.rs
let version = check_for_vassal_file(file.file_path(),file)?;
if version != "" {
let mod_version = version.parse::<Version>()?; // .await perhaps?
let rel_version = self.db.get_release_version(release).await?;
if mod_version != rel_version {
return Err(AddFileError::ReleaseVersionMismatch(
mod_version, rel_version
));
}
}
Oh, and in line 371 of GameSection
perhaps add the paragraph
<p>
Game box images can be PNG, GIF, JPEG, SVG, AVIF, or WEBP.
Images shold be no bigger than 200px × 200px, to not take up too
much space on the page.
</p>
With this kind of information on the page, I think many user errors can be prevented.
Ah, and another issue - when I add or change the game box image on a project page and press the ✓ I get the error
APIError: 500 Internal Server Error: error returned from database: (code: 787) FOREIGN KEY constraint failed
but if I click ✓ again, then all is good and the image is set or changed. Whether this is due to the project_id
or user_id
foreign key, I cannot tell. This does not happen when editing other fields in the GameSection
interface.
Yours,
Christian
Yes. This is what I was trying to convey above.
Fixed:
- afrika_korps_cholmcc
- afrika_korps_stiglr
- afrika_korps_cgmclellan
- afrika_korps_wga
- anzio_beachhead_unknown
- anzio_beachhead_cholmcc
- battle_skalla
- battle_cholmcc
- battle_for_moscow_cholmcc
- battle_for_moscow_unknown
- battle_for_moscow_operation_typhoon_expansion_json99
- battle_for_moscow_operation_typhoon_olivier
- d_day_3rd_ed_crispy1critter
- d_day_3rd_ed_woody8297
- d_day_3rd_ed_cholmcc
- d_day_2nd_ed_brian448
- gettysburg_125th_anniversary_wga
- gettysburg_125th_anniversary_cholmcc
- napoleon_at_waterloo_cholmcc
- napoleon_at_waterloo_2nd_ed_stephen_oliver
- napoleon_at_waterloo_3rd_ed_davejm
- panzerarmee_afrika_cholmcc
- panzerarmee_afrika_luc_liu
- panzerarmee_afrika_william_hay_spi
- panzerarmee_afrika_gamer94501 → This one already had an independent page.
- the_drive_on_metz_cholmcc
- the_drive_on_metz_2nd_ed_davout
Looking at Source of the Nile.
What I did.
I did not create a split but uploaded a new version of my Source of the Nile module so I don’t think I broke the don’t re-upload rule there, however, I did move the other person’s file which I realize now, I shouldn’t have because it now looks like it was my module which it isn’t
So based on your original instruction should I go ahead and create two new Source of the Nile pages, and request you move my 1.5.0 file to my project page and move the other module by Brian448 to that page.
I’ll wait for your input before I act so I don’t screw it up further.
One more thing: such requests sent via this public forum, or elsewhere (email?).

One more thing: such requests sent via this public forum, or elsewhere (email?).
Please send new requests or questions about individual modules via private message. It’s easier for me to track that way, as opposed to it getting lost in this very long thread.
I tried to upload a version 2.0.0 of The British Way, and got this message:
APIError: 502 Bad Gateway: 502 Bad Gateway
Bad Gateway
The proxy server received an invalid response from an upstream server.
It seems that there is nothing I can do to change this situation, or is there?
There is nothing you can do other than providing more context. What was the filename? Approximately when did you try uploading it?
The filename is British_Way_v2.0.0.vmod.
The upload finished shortly after 20:00 EST.

Fixed:
…
- panzerarmee_afrika_gamer94501 → This one already had an independent page.
Yeah, that page should not have been ported from the old Wiki pages to GLS. I would recommend you remove project 2392
and fix-up panzerarmee_afrika_gamer94501
instead.
Also, you are missing the_battle_of_agincourt_kevos4 (old wiki page). It was in the JSON data I sent you. Did you do the fixes by hand? The JSON data I posted was meant to help you automatise it.
Oh, and you can delete the projects 131, 216, 418, 449, 904, 1403, 2197, 2387, 3210 as they are now split.
Any case, great that you did it. Thanks.
Yours,
Christian

Also, you are missing the_battle_of_agincourt_kevos4 (old wiki page). It was in the JSON data I sent you. Did you do the fixes by hand? The JSON data I posted was meant to help you automatise it.
I skipped The Battle of Agincourt because it wasn’t in the original llist you gave.
Note also that all the URLs were wrong in the JSON—they should have referred to the modules already in storage, not the newly uploaded ones.

Note also that all the URLs were wrong in the JSON—they should have referred to the modules already in storage, not the newly uploaded ones.
You could have told me that what was you wanted, and I would happily have made you a new JSON, for including tags and so on.
Yours,
Christian
I just tried it again without my VPN, but I got the same result:
APIError: 502 Bad Gateway: 502 Bad Gateway
Bad Gateway
The proxy server received an invalid response from an upstream server.
The time was 9:50 EST, and the filename was still British_Way_v2.0.0.vmod
Is there anything else you need?
- 131 has tags copied to projects split from it.
- 216 is deleted, tags copied to projects split from it.
- 418 is deleted, tags copied to projects split from it.
- 449 has tags copied to projects split from it.
- 904 has tags copied to projects split from it.
- 1403 has tags copied to projects split from it.
- 2197 has tags copied to projects split from it.
- 2387 has tags copied to projects split from it.
- 3147 has tags copied to projects split from it.
- 131 has had players notified that they should add themselves to the new split pages.
- 449 has had players notified that they should add themselves to the new split pages.
- 904 has had players notified that they should add themselves to the new split pages.
- 1403 has had players notified that they should add themselves to the new split pages.
- 2197 has had players notified that they should add themselves to the new split pages.
- 2387 has had players notified that they should add themselves to the new split pages.
- 3210 has had players notified that they should add themselves to the new split pages.
- 131 is deleted.
- 449 is deleted.
- 904 is deleted.
- 1403 is deleted.
- 2197 is deleted.
- 2387 is deleted.
- 3210 is deleted.
(Catching up… )

I figured out what was happening with the inconsistent reporting of the properties of
XMLHttpRequest
: Logging to the console happens asynchronously, so if you dump an object to it you get the state of that object at the time the console serializes it to a string, which is not necessarily what it was at the point when you logged it. This is sanity-destroying if you don’t know thatconsole.log()
works this way contra to the behavior of basically every other logger anyone has ever designed.Rant: Why the af would you want a logger that prints the value something has at some arbitrary time in the future instead of the value it had when you did the logging? It’s like somebody was told to add logging, but didn’t understand what logging is.
An example of AI coding?? Looks good on the surface but…

An example of AI coding?? Looks good on the surface but…
console.log()
has existed in browsers for maybe 15 years at this point. Its poor design is entirely organic.

can’t upload
I have the same problem. Has anyone answered this question? (I haven’t seen it.) A step by step process would be very much appreciated.
Frank 6/22/25
Let me clarify: I was replying to Werefish not Segmelo. I’m not getting any error messages because I haven’t uploaded the module. I haven’t uploaded the module because there are no instructions on how to do so. Where do you go, what button do you click, how do you submit a module? This is insane. The old library had instructions and boxes to fill in. WTF!! This shouldn’t be difficult.