Using OpenEDX with IPv6 dual stack networking

Hello everyone,

reaching out to the community to verify if anyone is using OpenEDX in an IPv6 only or dual stack environment? We’re currently running dual stack and most of the services are working just fine when accessed using IPv6, the only issue we have is that file submissions are not working.

The POST request itself looks the same between IPv4 and IPv6: POST https://learn.our-url.com/courses/course-v1:OurOrg+MKSP-FAB+v1/xbl[…]m+block@problem1/handler/xmodule_handler/problem_check

This however returns a non-successful response:

{
    "success": "incorrect",
    "contents": "\n\n\n\n<h3 class=\"hd hd-3 problem-header\" id=\"problem1-problem-title\" aria-describedby=\"block-v1: OurOrg+MKSP-FAB+v1+type@problem+block@problem1-problem-progress\" tabindex=\"-1\">\n  Upload deines .nc Files\n</h3>\n\n<div class=\"problem-progress\" id=\"block-v1: OurOrg+MKSP-FAB+v1+type@problem+block@problem1-problem-progress\"></div>\n\n<div class=\"problem\">\n  <div>\n  <div class=\"wrapper-problem-response\" tabindex=\"-1\" aria-label=\"Question 1\" role=\"group\"><section id=\"filesubmission_problem1_2_1\" class=\"filesubmission\">\n  <div class=\"grader-status file\">\n\n    <span class=\"None\" id=\"status_problem1_2_1\">None</span>\n    <p class=\"debug\"/>\n\n    <input type=\"file\" name=\"input_problem1_2_1\" id=\"input_problem1_2_1\" value=\"['asset-v1_ OurOrg+MKSP-FAB+v1+type@asset+block@spannpratze-50.nc']\" multiple=\"multiple\" data-required_files=\"[]\" data-allowed_files=\"[]\" aria-label=\"\"/>\n  </div>\n    <div class=\"message\" tabindex=\"-1\">Unable to deliver your submission to grader (Reason: cannot connect to server). Please try again later.</div>\n</section></div>\n</div>\n  <div class=\"action\">\n    <input type=\"hidden\" name=\"problem_id\" value=\"Upload deines .nc Files\" />\n\n    <div class=\"problem-action-buttons-wrapper\">\n      <span class=\"problem-action-button-wrapper\">\n          <button type=\"button\" class=\"reset problem-action-btn btn-link btn-small\" data-value=\"Reset\"><span aria-hidden=\"true\">Reset</span><span class=\"sr\">Reset your answer</span></button>\n      </span>\n    </div>\n    <div class=\"submit-attempt-container\">\n      <button type=\"button\" class=\"submit btn-brand\" data-submitting=\"Submitting\" data-value=\"Absenden\" data-should-enable-submit-button=\"True\" aria-describedby=\"submission_feedback_problem1\" >\n          <span class=\"submit-label\">Absenden</span>\n      </button>\n\n      <div class=\"submission-feedback \" id=\"submission_feedback_problem1\">\n        <span class=\"sr\">Some problems have options such as save, reset, hints, or show answer. These options follow the Submit button.</span>\n      </div>\n    </div>\n  </div>\n    \n\n\n<div class=\"notification warning notification-gentle-alert\n      is-hidden\"\n     tabindex=\"-1\">\n    <span class=\"icon fa fa-exclamation-circle\" aria-hidden=\"true\"></span>\n    <span class=\"notification-message\" aria-describedby=\"problem1-problem-title\">\n    </span>\n    <div class=\"notification-btn-wrapper\">\n        <button type=\"button\" class=\"btn btn-default btn-small notification-btn review-btn sr\">Review</button>\n    </div>\n</div>\n\n    \n\n\n<div class=\"notification warning notification-save\n      is-hidden\"\n     tabindex=\"-1\">\n    <span class=\"icon fa fa-save\" aria-hidden=\"true\"></span>\n    <span class=\"notification-message\" aria-describedby=\"problem1-problem-title\">None\n    </span>\n    <div class=\"notification-btn-wrapper\">\n        <button type=\"button\" class=\"btn btn-default btn-small notification-btn review-btn sr\">Review</button>\n    </div>\n</div>\n\n    \n    \n\n\n<div class=\"notification general notification-show-answer\n      is-hidden\"\n     tabindex=\"-1\">\n    <span class=\"icon fa fa-info-circle\" aria-hidden=\"true\"></span>\n    <span class=\"notification-message\" aria-describedby=\"problem1-problem-title\">Answers are displayed within the problem\n    </span>\n    <div class=\"notification-btn-wrapper\">\n        <button type=\"button\" class=\"btn btn-default btn-small notification-btn review-btn sr\">Review</button>\n    </div>\n</div>\n\n</div>\n\n<script>\n    function emit_event(message) {\n        parent.postMessage(message, '*');\n    }\n</script>\n",
    "progress_changed": true,
    "current_score": 0.0,
    "total_possible": 100.0,
    "attempts_used": 11
}

The error message in there is Unable to deliver your submission to grader (Reason: cannot connect to server). Please try again later, however I could not find any error in the log files or any failed HTTP request in the browser tools. Anyone else using IPv6?

@dave - any thoughts on this grader issue?

I’ve never run the platform in an environment using IPv6, but I can’t think of why that should affect file uploads.

@Wasabi: What release are you running? Do you have the XQueue service running? Is it okay for you to post the OLX for your problem from the export file?

Hi @dave,

my apologies for not coming back earlier, I was on an extended business trip and can only follow up now. We’ve done some troubleshooting today and found out that IPv6 was likely a deceptive hint, it does seem to be unrelated.

The error we’re seeing in the logs is that the XQueue service is aborting the connection:

xqueue-1           | [pid: 6|app: 0|req: 195843/529126] 172.19.0.9 () {36 vars in 501 bytes} [Mon Jun 23 03:53:45 2025] POST /xqueue/submit/ => generated 0 bytes in 15 msecs (HTTP/1.1 302) 4 headers in 142 bytes (31 switches on core 0)
lms-1              | 2025-06-23 07:53:45,614 ERROR 29 [xmodule.capa.xqueue_interface] [user 52] [ip xx.xx.xx.xx] xqueue_interface.py:146 - ('Connection aborted.', ConnectionResetError(104, 'Connection reset by peer'))

So far it looks like it’s related to the file size. We have an upper limit of 4MB configured. Any file bigger than 4MB is rejected immediately, that is expected. Smaller files are where it gets tricky:

  • Everything smaller than 2.5MB goes through without issues in our tests
  • Files bigger than 2.5MB but smaller than 4MB sometimes to through, sometimes don’t.
  • It doesn’t seem time related, a 2.5M file got refused after 800ms, while a 2M file went through after 1.6s.

If the request doesn’t go through, there’s no file to be found in the mounted media folder (/home/ansible/.local/share/tutor/data/xqueue/media/openedx).

Regarding your questions:

  • We’re running tutor version 19.0.0 and therefore Sumac release
  • XQueue Service is running:
$ tutor local status
docker compose -f /home/ansible/.local/share/tutor/env/local/docker-compose.yml -f /home/ansible/.local/share/tutor/env/local/docker-compose.prod.yml --project-name tutor_local ps
NAME                            IMAGE                                        COMMAND                  SERVICE           CREATED         STATUS       PORTS
tutor_local-caddy-1             docker.io/caddy:2.7.4                        "caddy run --config …"   caddy             17 months ago   Up 4 weeks   443/tcp, 2019/tcp, 443/udp, 172.17.0.1:8081->80/tcp
tutor_local-cms-1               docker.io/overhangio/openedx:19.0.0          "uwsgi /openedx/uwsg…"   cms               3 months ago    Up 4 weeks   8000/tcp
tutor_local-cms-worker-1        docker.io/overhangio/openedx:19.0.0          "celery --app=cms.ce…"   cms-worker        3 months ago    Up 4 weeks   8000/tcp
tutor_local-lms-1               docker.io/overhangio/openedx:19.0.0          "uwsgi /openedx/uwsg…"   lms               3 months ago    Up 4 weeks   8000/tcp
tutor_local-lms-worker-1        docker.io/overhangio/openedx:19.0.0          "celery --app=lms.ce…"   lms-worker        3 months ago    Up 4 weeks   8000/tcp
tutor_local-meilisearch-1       docker.io/getmeili/meilisearch:v1.8.4        "tini -- /bin/sh -c …"   meilisearch       5 months ago    Up 4 weeks   7700/tcp
tutor_local-mfe-1               docker.io/overhangio/openedx-mfe:19.0.0      "caddy run --config …"   mfe               5 months ago    Up 4 weeks   80/tcp, 443/tcp, 2019/tcp, 443/udp
tutor_local-mongodb-1           docker.io/mongo:7.0.7                        "docker-entrypoint.s…"   mongodb           5 months ago    Up 4 weeks   27017/tcp
tutor_local-mysql-1             docker.io/mysql:8.4.0                        "docker-entrypoint.s…"   mysql             5 months ago    Up 4 weeks   3306/tcp, 33060/tcp
tutor_local-redis-1             docker.io/redis:7.2.4                        "docker-entrypoint.s…"   redis             5 months ago    Up 4 weeks   6379/tcp
tutor_local-xqueue-1            docker.io/overhangio/openedx-xqueue:19.0.0   "/bin/sh -c 'uwsgi  …"   xqueue            5 months ago    Up 4 weeks   8000/tcp
tutor_local-xqueue-consumer-1   docker.io/overhangio/openedx-xqueue:19.0.0   "sh -e -c 'while tru…"   xqueue-consumer   5 months ago    Up 4 weeks   8000/tcp

Just wondering right now whether its a problem that xqueue-consumer is running too, as we’re having our own xqueue watcher application outside

To be honest I’m not 100% sure what you mean by OLX, the problem definition looks something like this:

<problem>
  <coderesponse queuename="openedx">
    <filesubmission/>
    <codeparam>
      <grader_payload>{"grader_id": "fa4ca534-6f00-42c9-a82d-7f740c9090af"}</grader_payload>
    </codeparam>
  </coderesponse>
</problem>

The grader_id is something our xqueue watcher does internally to decide which grader should pick up the submission.