Vodmill docs
v1.0.0
Get help
● Ship · When something is wrong

Troubleshooting
the usual problems and their fixes.

Start with two places: the server log (journalctl -u vodmill -n 100 or docker logs vodmill) and the console's System health and Status pages. Most problems are named there.

Server logSystem healthStatus checks

01The server does not start

What you seeCause and fix
Cannot find module …/dist/src/server/index.jsThe build was not run. npm run build in the product folder.
An error about better-sqlite3 or a missing bindingNo prebuilt database driver for your system. Install python3 make g++, then npm ci again.
A syntax error, or process.loadEnvFile is not a functionNode.js is too old. node --version must be 22.12 or newer.
EADDRINUSESomething else uses the port. Change PORT in .env (and in the proxy), or stop the other program.
"This database was last used by Vodmill X, but this code is Y."You installed an older version over newer data. Install X or newer (Updating).
EACCES on the data folderThe service user does not own the folder: sudo chown -R vodmill:vodmill /opt/vodmill.

02I cannot find the setup code, or it is refused

The code is printed in the server log on every start until the owner exists: journalctl -u vodmill | grep -A 3 "setup code". Any printed code works until the owner is created. If the owner already exists and you lost the password, use recover-owner.js (First steps).

03"Public URL is https" stays red, or sign-in does not stick

  • Set PUBLIC_URL=https://your-domain in .env and restart, or fill the Server section in the console.
  • Open the app through the https address, not through http://server-ip:8787: with an https public URL the cookies are marked Secure and a plain http page cannot keep the session.
  • Behind nginx, pass Host and X-Forwarded-Proto as in Installation.

04ffmpeg or ffprobe is "not found"

sudo apt install -y ffmpeg installs both. If they are installed but not on the service's PATH, set full paths in .env and restart:

which ffmpeg ffprobe
# then in .env
FFMPEG_PATH=/usr/bin/ffmpeg
FFPROBE_PATH=/usr/bin/ffprobe

05Uploads fail or stop

What you seeCause and fix
Every piece fails with 413 behind nginxclient_max_body_size is too small. Set 64m (Installation).
"This file is larger than N GB, the limit on this server."Raise "Largest upload (GB)" under System, Rendering.
"Upload a video file: MP4, MOV, MKV or WebM."Other containers are not accepted. Export the video again as MP4.
"This video has no sound."Clips are found through speech; a source needs an audio track.
"Ten uploads of this workspace are unfinished."Finish or delete one in the library. Uploads nobody finishes are removed after two days.
An upload stopped half-wayOpen the library and choose "Continue the upload" with the same file.

06A source cannot be analysed, or the analysis fails

What you seeCause and fix
Status check "Transcription is set up" is redThe chosen provider has no key, or the whisper.cpp paths are wrong (Transcription).
"… is rate-limiting this key or its quota is used up"Your transcription provider's limit. Check its dashboard, or switch provider.
"whisper.cpp did not write its result. Is the model file a ggml model?"The model path points at the wrong file. It must be a ggml-*.bin model.
"This video runs N minutes; the … plan allows M."The plan's "Longest source video". Change the plan or the workspace's plan.
"The … plan analyses N minutes a month and M are used."The plan's monthly minutes.
"No clips found"Nothing passed the bar. Try other lengths or add notes, then analyse again.
Clips are picked but without AI titlesNo Anthropic key: the built-in picker was used. See the console's AI usage page for failed calls when a key is set.

When a step fails, the credits charged for it are returned and the source shows the error. "Analyse again" starts over; a finished transcript is reused.

07Renders fail, wait or look wrong

What you seeCause and fix
Renders wait for a long timeOne render runs at a time by default, and one per workspace. Check the console's Render queue. More cores first, then "Renders at the same time".
The server becomes slow or the process is killed during rendersToo much parallel work for the machine's memory. Set "Renders at the same time" and "Sources analysed at the same time" back to 1.
"Face model not found: put face_detection_yunet_2026may.onnx in the models folder or set VODMILL_YUNET_MODEL"The models folder is missing next to the app (the Docker image contains it). Put the folder from the package back, or set VODMILL_YUNET_MODEL in .env to the file's full path.
"The source file of this clip is gone, so it cannot be rendered."The source's files were deleted or not restored (Backups).
"60 fps renders are not part of the … plan."60 fps needs "Allow 60 fps renders" and the plan's limit.
The crop follows the wrong personSet the layout by hand (Layouts).
Captions show boxes for some lettersThe bundled fonts cover Latin scripts. Other scripts need a system font on the server.
Free disk is "low" or "critical" on System healthDelete old sources, set "Delete render files after (days)", or add disk.

08Other answers you may see

What you seeCause and fix
"The server is working out the framing of other clips. Try again in a few seconds." (429 with retry-after: 5)Face tracking for the editor's preview is limited to a few clips at once for the whole server. Meanwhile the editor's preview keeps its approximate framing and asks again after the next change to the clip; nothing is lost.
"Too many links that do not exist were opened from this address. Wait a few minutes." (429)The guard against guessing share links (Security). Real links are not counted.
"This service is not available in your country." (451)The visitor's country is on your blocked list (Security).
"The canceled analysis is still stopping. Try again in a moment." (409)A canceled analysis is still letting go of its step. Start the new analysis a few seconds later.

09Import from a link does not work

What you seeCause and fix
"Importing from a link is switched off on this server."The switch is off, or no allowed kind of link is usable: YouTube, Twitch and Kick need the yt-dlp path, direct links must be ticked under "Allowed sites" (Imports).
"This link cannot be imported here. Allowed: …"The link's site is not among the allowed ones on this server. The sentence lists what is allowed.
"Importing from a link is not part of the … plan."Switch on the plan's "Import from a link".
"yt-dlp could not be started at …"Wrong path, or the service user may not run it. With Docker the path must exist inside the container.
"Instagram and TikTok links cannot be imported."By design. Upload the original file.
"This video is private or needs a sign-in" / "not available any more"The video cannot be reached publicly.
Imports that worked now fail for one siteThe site changed. Updating the program is the operator's task.

11E-mails do not arrive

  • The Resend key and the Sender must both be set, and the sender's domain verified in Resend.
  • The public URL must be set, or reset e-mails are not sent at all.
  • Meanwhile: invite links are shown on the page, and the console's Users page makes a password reset link you can send yourself.

12Campaign views are not updating

  • Status checks "Campaign views can be counted automatically" and "Campaign view tracking is running" say which key is missing or when the last check ran.
  • Only YouTube and Twitch are automatic. For other platforms the clipper uploads a screenshot and a reviewer confirms it.
  • Views are read hourly for 48 hours, then daily. "Read views now" on the console's Campaigns page checks at once.
  • "Counted views can be lower than the platform shows": open the submission for the reasons (the tracking window, the baseline when views count from submission).
  • A clip cannot be approved when the budget is fully reserved: the brand raises the budget.

13Publishing problems

What you seeCause and fix
Google shows redirect_uri_mismatchThe redirect URI in your OAuth client must be exactly <public URL>/api/publish/youtube/callback.
Only some people can connect; connections end after a weekYour Google consent screen is in Testing (Publishing).
A channel shows "reconnect"Access was withdrawn or expired. Connect the channel again.
Posts fail with a quota messageYour Google project's daily upload quota, shared by all customers, or the channel's own daily limit.
A Postiz address is refusedIt must be https on port 443 and reachable from the internet.
Scheduled posts do not go outStatus check "Scheduled posts are going out"; publishing or that channel kind may be switched off.

14API and webhooks

  • 403 The API is turned off on this server.: System, Public API.
  • 402 The workspace's plan does not include the API.: the plan's "REST API and webhooks".
  • 401: the header must be Authorization: Bearer vdm_….
  • A webhook that never arrives: Developers, "Deliveries" shows the result of each try. The address must be https and public.
  • The same event arrives more than once: a failed delivery is tried up to 3 times with the same event id. Answer 2xx within 10 seconds and ignore ids you already handled (Webhooks).
  • Signature checks fail: verify the raw body, and check the server clocks (a difference over five minutes is refused).
  • 413 Request too large: a JSON body over the limit (Security).
  • 422 with a sentence: invalid input, in the API and in the app alike (publishing forms included). The sentence says what to correct.

15Still stuck

See Support for what to include in a request. Never send API keys, .env, ADMIN_SECRET_KEY, passwords or backups.