Large File Corrupted with mostly empty bytes on upload

I am trying to diagnose a file corruption that occurred after a user uploaded a 3.0gb file to the server. Upon downloading the file it was still exactly the same size as the file that was originally uploaded down to the exact byte count, but inspecting the bytes of the file it could be seen that most of the file was now 0s with the only non-zero bytes starting at address: 0xAF800000 and onward to the end of the file.

Looking through the logs, I did not see any errors through the time of the upload.

One theory I had was that the user was uploading the file during the time when our server restarts for a backup- but checking the timestamps of our backups and the server’s logs it was determined that the backup occurred 2 hours before the user attempted their upload.

Another theory I had was that the network drive on which our seafile server’s data drive is mounted was temporarily disconnected by our server provider, Hetzner. Hetzner occasionally disconnects storage boxes for maintenance but they always provide a log of when this happens. There were no such incidents during the time the user attempted their upload.

Looking through the forums here, the closest post that resembles my issue was this one: SeaDrive client 2 cached file corruption (can’t link directly because my account is too young) however, the user uploaded their file through the web UI.

When the user uploaded the same file again, it uploaded fine with no corruption.

Server Details

  • Community Edition
  • Version 13.0.21
  • Authentication through OIDC
  • Deployed with Docker
  • Volumes are mounted on a CIFS network drive

Any help diagnosing this issue or coming up with mitigations would be greatly appreciated.

You can run fsck on the library, to see whether Seafile consider that file corrupted. Corruptions in Seafile are usually caused by missing blocks. In such cases, you usually cannot download the file at all. If all the blocks are considered sound by Seafile, the cause may be that the file was already corrupted before it was sent to Seafile server, perhaps by some gateway or firewall.

I have run seafile-fsck now and do not see the file listed as corrupted.

# ./seaf-fsck.sh

Starting seaf-fsck, please wait ...

[2026-06-09 19:44:11] [INFO] fsck.c(677): Running fsck for repo d3bebb10-42f5-4054-9ce7-cad8b3eb40a9.
[2026-06-09 19:44:11] [INFO] fsck.c(498): Checking file system integrity of repo Rec Room Archive(d3bebb10)...
[2026-06-09 19:55:11] [INFO] fsck.c(741): Fsck finished for repo d3bebb10.

[2026-06-09 19:55:11] [INFO] fsck.c(677): Running fsck for repo 5e9e1adc-88fc-4395-966b-97aa6508e36f.
[2026-06-09 19:55:11] [INFO] fsck.c(498): Checking file system integrity of repo My Library(5e9e1adc)...
[2026-06-09 19:55:11] [INFO] fsck.c(741): Fsck finished for repo 5e9e1adc.

[2026-06-09 19:55:11] [INFO] fsck.c(677): Running fsck for repo 4241c055-0ef8-44f8-842a-d93bf6867185.
[2026-06-09 19:55:11] [INFO] fsck.c(498): Checking file system integrity of repo My Library(4241c055)...
[2026-06-09 19:55:11] [INFO] fsck.c(741): Fsck finished for repo 4241c055.

[2026-06-09 19:55:11] [INFO] fsck.c(677): Running fsck for repo 343518b7-7174-40de-bca2-3c231191397e.
[2026-06-09 19:55:11] [INFO] fsck.c(498): Checking file system integrity of repo My Library(343518b7)...
[2026-06-09 19:55:30] [INFO] fsck.c(741): Fsck finished for repo 343518b7.

[2026-06-09 19:55:30] [INFO] fsck.c(677): Running fsck for repo 2bb952ad-76d2-4448-b15f-e2a12f313d2d.
[2026-06-09 19:55:31] [INFO] fsck.c(498): Checking file system integrity of repo My Library(2bb952ad)...
[2026-06-09 19:55:31] [INFO] fsck.c(741): Fsck finished for repo 2bb952ad.

[2026-06-09 19:55:31] [INFO] fsck.c(677): Running fsck for repo 0ad905b2-245b-4ea5-b727-b37a5b4568f2.
[2026-06-09 19:55:31] [INFO] fsck.c(498): Checking file system integrity of repo My Library Template(0ad905b2)...
[2026-06-09 19:55:31] [INFO] fsck.c(741): Fsck finished for repo 0ad905b2.

seaf-fsck run done

Done.

We are able to download the file just fine as well as rename it and move it around. Seafile doesn’t seem to know that something has happened.

The user was able to re-upload the file and it arrived without corruption. If there was a firewall causing corruption I would have expected that to cause corruption every time the user tried to upload the file.

Is there a way to diagnose this further? I’ve only just spun up this server a few weeks ago and the fact that we’ve already seen a silent file corruption has completely eroded trust in any file upload. Alternatively, I’m interested in a potential mitigation; a way for users to know if the file matches what they originally uploaded once it has finished uploading.

Hello @Motocross2573 ,

You can troubleshoot this issue using the following steps:

First, open the directory containing the file that was previously reported as corrupted. Then open the browser’s Developer Tools. After refreshing the page, you should be able to see the relevant request in the Network tab (as shown in the screenshot). From this request, you can obtain the file’s obj_id.

Next, use the file history to access the snapshot from when the file was first uploaded in a corrupted state. Using the browser’s Developer Tools again, obtain the obj_id of the same file from that snapshot.

Compare the two obj_id values:

  • If they are the same, it indicates that the file was uploaded to the server correctly and completely. In this case, the problem is more likely related to writing the file blocks to storage or to the actual download process experienced by the user.

  • If they are different, it indicates that the file was already corrupted when it was uploaded to the server. This suggests that the issue may have occurred during the file transfer process.

Please compare the two obj_id values first to determine which scenario applies.

And, are you using go fileserver or c fileserver?

Thank you for these steps. I’ve verified that the two ids are the same for the corrupted file as it is currently and the corrupted file as it was in the snapshot it was uploaded in.

I have also been digging through various logs related to the incident. Here, for instance, are two errors reported by my nginx reverse proxy at the time when the file upload was completed.

2026/06/03 10:23:51 [error] 3678876#3678876: *259861 upstream timed out (110: Connection timed out) while reading response header from upstream, client: [REDACTED Client IP], server: drive.[REDACTED].com, request: "POST /seafhttp/upload-aj/1c729ff0-6062-4407-9667-23a862e97a69?ret-json=1 HTTP/1.1", upstream: "http://127.0.0.1:8083/seafhttp/upload-aj/1c729ff0-6062-4407-9667-23a862e97a69?ret-json=1", host: "drive.[REDACTED].com", referrer: "https://drive.[REDACTED].com/library/d3bebb10-42f5-4054-9ce7-cad8b3eb40a9/Rec%20Room%20Archive/Games"
2026/06/03 10:23:51 [error] 3678876#3678876: *259861 client intended to send too large body: 6743715 bytes, client: [REDACTED Client IP], server: drive.[REDACTED].com, request: "POST /seafhttp/upload-aj/1c729ff0-6062-4407-9667-23a862e97a69?ret-json=1 HTTP/1.1", upstream: "http://127.0.0.1:8083/seafhttp/upload-aj/1c729ff0-6062-4407-9667-23a862e97a69?ret-json=1", host: "drive.[REDACTED].com", referrer: "https://drive.[REDACTED].com/library/d3bebb10-42f5-4054-9ce7-cad8b3eb40a9/Rec%20Room%20Archive/Games"

from that error: 6,743,715 bytes is very very close to the 6,742,322 bytes that were successfully written to seafile.The rest of the 2,951,143,730 bytes were all 0s.

Here are the nginx access logs from around the time that the file finished uploading. Not the 413 that was caught in the error logs. Also note the additional POST request that succeeded after the 413 error.

[REDACTED Client IP] - - [03/Jun/2026:10:22:43 +0000] "POST /seafhttp/upload-aj/1c729ff0-6062-4407-9667-23a862e97a69?ret-json=1 HTTP/1.1" 200 17 "https://drive.[REDACTED].com/library/d3bebb10-42f5-4054-9ce7-cad8b3eb40a9/Rec%20Room%20Archive/Games" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36"
[REDACTED Client IP] - - [03/Jun/2026:10:22:48 +0000] "POST /seafhttp/upload-aj/1c729ff0-6062-4407-9667-23a862e97a69?ret-json=1 HTTP/1.1" 200 17 "https://drive.[REDACTED].com/library/d3bebb10-42f5-4054-9ce7-cad8b3eb40a9/Rec%20Room%20Archive/Games" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36"
[REDACTED Different Non-Associated Client IP] - - [03/Jun/2026:10:22:54 +0000] "POST /seafhttp/repo/head-commits-multi/ HTTP/1.1" 200 83 "-" "Seafile/9.0.18 (Windows NT)"
[REDACTED Different Non-Associated Client IP] - - [03/Jun/2026:10:23:24 +0000] "POST /seafhttp/repo/head-commits-multi/ HTTP/1.1" 200 83 "-" "Seafile/9.0.18 (Windows NT)"
[REDACTED Client IP] - - [03/Jun/2026:10:23:52 +0000] "POST /seafhttp/upload-aj/1c729ff0-6062-4407-9667-23a862e97a69?ret-json=1 HTTP/1.1" 413 578 "https://drive.[REDACTED].com/library/d3bebb10-42f5-4054-9ce7-cad8b3eb40a9/Rec%20Room%20Archive/Games" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36"
[REDACTED Different Non-Associated Client IP] - - [03/Jun/2026:10:23:54 +0000] "POST /seafhttp/repo/head-commits-multi/ HTTP/1.1" 200 83 "-" "Seafile/9.0.18 (Windows NT)"
[REDACTED Different Non-Associated Client IP] - - [03/Jun/2026:10:24:24 +0000] "POST /seafhttp/repo/head-commits-multi/ HTTP/1.1" 200 83 "-" "Seafile/9.0.18 (Windows NT)"
[REDACTED Different Non-Associated Client IP] - - [03/Jun/2026:10:24:55 +0000] "POST /seafhttp/repo/head-commits-multi/ HTTP/1.1" 200 83 "-" "Seafile/9.0.18 (Windows NT)"
[REDACTED Different Non-Associated Client IP] - - [03/Jun/2026:10:25:25 +0000] "POST /seafhttp/repo/head-commits-multi/ HTTP/1.1" 200 83 "-" "Seafile/9.0.18 (Windows NT)"
[REDACTED Different Non-Associated Client IP] - - [03/Jun/2026:10:25:55 +0000] "POST /seafhttp/repo/head-commits-multi/ HTTP/1.1" 200 83 "-" "Seafile/9.0.18 (Windows NT)"
[REDACTED Client IP] - - [03/Jun/2026:10:26:07 +0000] "POST /seafhttp/upload-aj/1c729ff0-6062-4407-9667-23a862e97a69?ret-json=1 HTTP/1.1" 200 98 "https://drive.[REDACTED].com/library/d3bebb10-42f5-4054-9ce7-cad8b3eb40a9/Rec%20Room%20Archive/Games" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36"
[REDACTED Client IP] - - [03/Jun/2026:10:26:07 +0000] "GET /media/img/file/256/video.png HTTP/1.1" 200 6912 "https://drive.[REDACTED].com/library/d3bebb10-42f5-4054-9ce7-cad8b3eb40a9/Rec%20Room%20Archive/Games" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36"

Is any of this significant?

Hello @Motocross2573 ,

If the IDs of the two files are identical, it indicates that the chunking used during the previous upload and the current one is the same. This is because the obj_id is calculated based on the file content.

Therefore, the issue is likely caused by a download error. You can check the Nginx logs during the download after the file upload has completed, and verify whether the returned file size matches the actual file size.

Oh sorry, I think I misunderstood. You wanted me to compare the obj_id of the successful upload of that file vs the corrupted upload. I will have to get back to you on that.

image

Alright, I’ve determined that in actuality, these two files (the corrupt version and the non-corrupt version) have two different obj_ids.

Sorry about that misunderstanding.

Hello @Motocross2573 ,

are you using go fileserver or c fileserver?

I’m using the docker image. I had to dig around to figure out how I might be able to know what fileserver I was using.

Currently, my seafile.conf is very sparse only having two configurations set. I figured most of the configuration was handled by the environmental variables. I can’t find a variable for that specific setting though.

In my seafile.conf I do not have this line:

[fileserver]
use_go_fileserver = true

Which I believe is the only way I could be using the go fileserver. If that’s the case, then I am not using the go fileserver and so instead am using the c fileserver.

Let me know if there’s another way in which the fileserver can be set to either go or c other than in the seafile.conf.

Hello @Motocross2573 ,

You can run the following command inside the seafile container:

ps -ef | grep fileserver

Then check the output to confirm whether the Go fileserver is being used.

Here’s what I get

root@b12d740b5dee:/opt/seafile# ps -ef | grep fileserver
root         109      89  0 04:51 ?        00:00:01 /opt/seafile/seafile-server-13.0.21/seafile/bin/fileserver -F /opt/seafile/conf -d /opt/seafile/seafile-data -l /opt/seafile/logs/fileserver.log -p /opt/seafile/seafile-server-13.0.21/runtime -P /opt/seafile/pids/fileserver.pid
root        8776    8763  0 05:46 pts/0    00:00:00 grep --color=auto fileserver

Hello @Motocross2573 ,

Thanks, you are currently using the go fileserver. I will check whether there is any issue related to the go fileserver in this regard.

Hello @Motocross2573 ,

Can you check if making any changes to the nginx configuration inside the seafile container? What does the current seafile nginx configuration look like?

The nginx config inside of the seafile container is as follows:

server {
    listen 80;

    client_max_body_size 10m;

    location / {
        proxy_pass http://127.0.0.1:8000/;
        proxy_read_timeout 310s;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host $server_name;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Connection "";
        proxy_http_version 1.1;

        add_header Access-Control-Allow-Origin *;
        client_max_body_size 0;
        access_log      /shared/seafile/logs/seahub.access.log seafileformat;
        error_log       /shared/seafile/logs/seahub.error.log;
    }

    location /seafhttp {
        rewrite ^/seafhttp(.*)$ $1 break;
        proxy_pass http://127.0.0.1:8082;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        client_max_body_size 0;
        proxy_read_timeout  36000s;

        proxy_buffering off;
        proxy_request_buffering off;

        access_log      /shared/seafile/logs/seafhttp.access.log seafileformat;
        error_log       /shared/seafile/logs/seafhttp.error.log;
    }

    location /seafdav {
        rewrite ^/seafdav$ /seafdav/ permanent;
    }

    location /seafdav/ {
        proxy_pass         http://127.0.0.1:8080/seafdav/;
        proxy_set_header   Host $host;
        proxy_set_header   X-Real-IP $remote_addr;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Host $server_name;
        proxy_read_timeout  1200s;
        client_max_body_size 0;

        access_log      /shared/seafile/logs/seafdav.access.log seafileformat;
        error_log       /shared/seafile/logs/seafdav.error.log;
    }

    location /:dir_browser {
        # Logo of WebDAV
        proxy_pass         http://127.0.0.1:8080/:dir_browser;
    }

    location /media {
        root /opt/seafile/seafile-server-latest/seahub;
    }

}

And the nginx config for our reverse proxy infront of the docker container is as follows:

server {
        ##
        # Custom error pages.
        ##
        include snippets/error-pages.conf;


        server_name drive.[REDACTED].com;
        location / {
                proxy_pass http://127.0.0.1:8083;

                client_max_body_size 512M;

                proxy_set_header Connection $http_connection;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;

        }


        location /sdoc-server/ {
                proxy_pass http://127.0.0.1:8084/;


                client_max_body_size 512M;
                proxy_set_header Connection $http_connection;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
        }

        location /socket.io {
                proxy_pass http://127.0.0.1:8084;

                # Start # These settings are necessary for proper function of web sockets.
                proxy_http_version 1.1;
                proxy_set_header Connection "upgrade";
                proxy_set_header Host $http_host;
                # End #

                client_max_body_size 512M;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;

        }


        listen 443 ssl; # managed by Certbot
        ssl_certificate /etc/letsencrypt/live/drive.[REDACTED].com/fullchain.pem; # managed by Certbot
        ssl_certificate_key /etc/letsencrypt/live/drive.[REDACTED].com/privkey.pem; # managed by Certbot
        include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}

server {
        if ($host = drive.[REDACTED].com) {
                return 301 https://$host$request_uri;
        } # managed by Certbot

        server_name drive.[REDACTED].com;
        listen 80;
        return 404; # managed by Certbot


}

Hello @Motocross2573 ,

You are currently using the go fileserver, so in theory nginx does not need to buffer requests. Therefore, I recommend using the following configuration for your reverse proxy infront of the docker container:

client_max_body_size 0;
proxy_read_timeout 36000s;
proxy_buffering off;
proxy_request_buffering off;

After applying this configuration, please observe whether file upload errors still occur.

I’ve added that to my nginx config. Over the next couple weeks we’ll be stess testing the server more as many large files will be getting uploaded. Hopefully that will validate if this change has fixed our issue. Thank you for all your help.