Troubleshoot a Failed Scan
Find out why a saneless command failed, starting from its exit code, and what to check next.
When a command fails it prints a line to stderr saying what failed, then a Try: line with the
next step to take, and exits with a non-zero code. The web UI shows the same failure on the job.
The exact wording of the messages may change between releases, so this page describes what you
see rather than quoting each message in full.
Start with the exit code
In a shell, echo $? right after the command prints its exit code.
| Exit code | Where to look |
|---|---|
| 0 | Nothing to look for |
| 1 | Scanner errors |
| 2 | Configuration errors, python-sane is not installed |
| 3 | Paperless errors |
| 4 | PDF assembly errors |
| 5 | Unexpected errors |
| 6 | Saved to the consume folder |
| 7 | Uploaded with a warning |
| 8 | Every page looked blank |
| 9 | The document may already be in paperless-ngx |
| 10 | Out of disk space |
| 129 | Interrupted by a signal |
| 130 | Cancelled scans |
| 141 | The output was cut off |
| 143 | Interrupted by a signal |
CLI Commands defines what each code means and lists the codes each command can return, and Use the CLI for Scripting shows how to branch on them in a script.
Scanner errors (exit 1)
The line starts with Scan error:. It says what saneless was doing and names the device, then
gives the scanner's own words. Those last words come from the scanner driver, so they are the part
to search for in your scanner's documentation.
What the common cases mean:
- No scanner found. saneless looked for a scanner and found none:
scanwithscanner.deviceempty, orauto-profiles. The configuration is not what is wrong. Check that the scanner is switched on and connected, or reachable over the network, then runsaneless devicesto see what SANE can find; see Scanner Host Discovery when the scanner is on another machine. - No paper detected in the feeder. The document feeder was empty when the scan started, or the source is set to the feeder on a scanner that has nothing loaded. Load the stack and scan again, or pick a flatbed profile.
- Every sheet fed was unreadable. The feeder pulled paper, but the scanner returned no page saneless could use. Check for a jam, a misfeed or a dirty feeder, then scan again.
- No pages were scanned. The scanner finished without returning any page at all. Check that the profile's source matches where the paper is. In a manual duplex scan, an empty second pass says so and names how many front pages the first pass scanned; reload the flipped stack and scan both sides again.
- Every page looked blank. This is not a scanner error and does not exit 1: the scanner returned pages and empty-page detection removed all of them. It exits 8; see Every page looked blank.
- The flip wait timed out. A manual duplex scan waited
operator_wait_timeout_secondsfor someone to flip the stack and nobody answered. A timeout is a failure, not a cancel. The front sides the first pass already scanned are kept: saneless assembles them into a PDF underfailed/in its data directory and names the path in the error. See Manual Duplex. - The flip prompt failed. Reading your answer failed while
saneless scanwas asking you to flip the stack, for example with an I/O error or input that could not be decoded. The cause is logged with its traceback, and the fronts are kept the same way a flip timeout keeps them. End of input is not a failure: Ctrl-D at the prompt cancels the scan (exit 130). A terminal or SSH session that closes at the prompt is not a cancel either: it is an interruption that keeps the fronts (exit 129). - A multi-page scan failed. With Multiple pages (or
saneless scan --multi-page), a scanner fault or an empty feeder does not end the scan once the document holds at least one page. saneless asks instead: "The last scan failed, so none of its pages were added.", followed by what the scanner reported, with Scan again, Finish document and Abort scan (n,fandaat the terminal). The failed scan adds nothing, so clear the scanner, put back every page from that scan, and scan again. An empty feeder -- Scan next page pressed before the next sheet was loaded -- brings up the same question. Only a failure on the first scan, or while re-scanning the only scan so far, ends the job with exit 1, as any scan failure does. The working directory running out of room still ends the job whatever the page count, with the pages kept so far saved underfailed/. If nobody answers the question, the document is finished with the pages kept (exit 7). See Scan a Multi-Page Document. - The multi-page prompt failed. Reading your answer at a
saneless scan --multi-pagequestion failed, for example with an I/O error. The scan fails with exit 1, and the pages kept so far are saved as a PDF underfailed/, with the path in the error. -
The scan stopped part-way through the stack. The scanner failed after some sheets had already been fed -- a jam, a misfeed, a page that took too long, or the working directory running out of room. Those sheets are not lost. saneless assembles them into a PDF under
failed/in its data directory, and the error names both the count and the path:Scanner error on page 40: Document feeder jammed. The 39 page(s) scanned before the error were preserved at /var/lib/saneless/failed/20260916-013255-4c8627dd-invoice-partial.pdfNothing is uploaded. Clear whatever stopped the feeder, then either scan the whole stack again and delete the preserved file, or keep it and scan only the sheets it is missing. Empty page detection is deliberately not applied to a preserved scan, so it shows exactly what the feeder picked up. saneless never deletes anything from
failed/; draining it is your job (see Docker volumes). - A page took too long. Each page has a time limit, on the feeder and on the flatbed alike. The limit scales with the resolution and page size the scanner agreed to, is never below 120 seconds and never above an hour: anything at 300 dpi gets 120 seconds, and an A4 colour page at 1200 dpi about 480. The line states the limit and the page it was worked out for, for example:Page 3 timed out after 480s, the limit for a colour page of 9921 x 14031 pixels at 1200 dpiA dropped network link mid-page is one cause, but not the only one: a slow USB or Wi-Fi link, or a high resolution the scanner is slow to deliver, can reach the limit too. Check the link first; if pages at a high resolution keep timing out, lower the profile's
resolution. Any sheets scanned before it are preserved as above. When the scanner did not answer the cancel either, the line ends; the scanner did not answer the cancel either, so saneless stopped it: saneless stopped the scan's process after ten seconds, as below. - The scanner has no source named the one in the profile. The line names the profile's source and every source the scanner offers, for example:The scanner has no source named 'Feeder'. It offers 'Flatbed', 'ADF'; set the profile's source to one of those names.saneless matches a profile's
sourceagainst the scanner's list ignoring case and surrounding spaces, and scans with the scanner's own spelling, soadffindsADF. A name that matches none is refused before any paper moves. A feeder name, or a name saneless does not recognise, is never swapped for another source; only a flatbed name may fall back to the scanner's Auto source, and when that sends the scan through the feeder the job ends with a warning (see Uploaded with a warning). If two of the scanner's sources differ only in case, the line says the profile's source matches more than one of them and lists them; setsourceto one of them exactly. - The scanner is set to 16 bits per sample. The line readsThe scanner <device> is set to 16 bits per sample, and saneless scans at 8. Choose an 8-bit mode, such as Gray or Color, in the profile.saneless sets the scanner to 8 bits per sample wherever the scanner allows it, so this appears only when the profile'smodecan be scanned at 16 bits alone. The scan is refused before any page. Set the profile'smodeto an 8-bit one. - The scanner stopped answering; saneless stopped it. Every scan runs in a process of its own, and saneless gives each step other than a page's read 30 seconds: starting the scanner library, opening the scanner, setting up the scan, closing it, restarting the library between passes, and finishing. A step that runs past that ends the process at once, and the line names the step, for example:The scanner stopped answering while opening the scanner; saneless stopped itThe pages scanned before it are preserved as above. Nothing else needs doing before the next scan: it starts a fresh process with a fresh connection to the scanner, and fails the same way if the scanner is still not answering. Check the link to the scanner first -- a network scanner that went away, a
sanedhost that restarted or stopped, a USB cable -- then power-cycle the scanner if it keeps happening at the same step. - The scanning process ended unexpectedly, or died. The line readsThe scanning process ended unexpectedly (exit status <n>)orThe scanning process died from <signal>, then the step. saneless did not stop it: the process that talks to the scanner ended by itself, often in the scanner library. When it ended with an exit status, its own line on saneless's stderr usually names the cause by type; a process that died from a signal writes no such line. The pages scanned before it are preserved, and the next scan starts a fresh process. If it keeps happening at the same step, run the scan with--verboseand report it.
To check that saneless can see the scanner at all, run:
saneless devices
If the scanner is missing from that list, or saneless runs in a container, work through Scanner Host Discovery.
The status strip and saneless devices ask SANE for scanners the same fresh way, in a new
short-lived process each time, so if the strip's Scanner row is red, pressing Check again after
fixing the cause is enough; a restart is only needed after changing saneless's own settings.
What the Scanner row says lists each Scanner
row, what fixes it, and whether pressing Check again or a restart clears it.
Configuration errors (exit 2)
A problem with the config file prints a header naming the file, then one line per problem, then a
Try: line. A TOML syntax error names the line and column where parsing stopped. Fix each line
listed and run the command again; Validation
describes the rules.
Other causes of exit 2, each a line naming the problem and then a Try: line with the fix:
- Unknown profile. The
--profilename is not a profile in the loaded config. Check the spelling against the[profiles.NAME]tables. - Manual duplex without a terminal. A profile with
duplex = "manual"needs someone to flip the stack, sosaneless scanrefuses it when stdin is not a terminal (cron, a pipe, CI). Run it from a terminal or scan from the web UI. --multi-pagewithout a terminal, or with manual duplex.saneless scan --multi-pageasks after every scan whether there is another page, so it is refused when stdin is not a terminal. It is refused for aduplex = "manual"profile too, because the two flows cannot be combined: scan without--multi-page, or choose another profile.servecannot start. The port is already in use, or the web server failed to start. Stop whatever holds the port or pass--port; when the web server itself failed, the cause is in the preceding log lines:servestreams its log to stderr rather than writing a file.servelogs these failures without a traceback: the line and itsTry:line say what to fix. SANE that will not start does not stopserve: the Scanner row reports it, and the log gives its reason (see Scanner Host Discovery).- The working directory cannot be prepared. The line names
tmp_dir(in[output]) and the reason: the directory was removed or cannot be created, or the disk is full. Check that it exists, that saneless can write to it, and that there is free space. - The working directory is not private. The line names
output.tmp_dir, its path and what is wrong with it: it is a symbolic link, it is not a directory, it belongs to another user, or its group or everyone can write to it. saneless keeps scanned pages there and will not use a directory someone else could change. Runchmod 700on a directory you own (the line gives the command), remove it so saneless creates it privately, or settmp_dirto another directory. - The job database cannot be used. The line starts with
Job database error:and names the database path and the reason: the file cannot be opened or is not a SQLite database, or its jobs table has a shape this version of saneless does not recognise. Check that the path is right, that saneless can read and write it and its directory, and that the file really is saneless's job database. If it is damaged, move it aside: saneless then starts with an empty job history, and the moved file is kept for inspection or restoring.saneless jobsonly reads the history, so it also refuses a job database at an older schema, and says so. Onlysaneless serveupgrades a job database: start it once with the same config, even on an install that otherwise only uses the CLI, stop it, then runsaneless jobsagain. paperless.urlorpaperless.tokenrefused. Spaces and line breaks around either value are ignored. What is left ofpaperless.urlmust be empty, or anhttp://orhttps://address that names a host and holds no user name or password. What is left ofpaperless.tokenmust be visible ASCII, with no spaces, line breaks or control characters inside it. A value that breaks these rules is refused when the config loads, so every command that reads the config exits 2 andservedoes not start. The line names the key and the rule, never the value, for example[paperless] token: Value error, must contain only visible ASCII characters: no spaces, line breaks or control characters inside it. See[paperless].paperless.urlnot set. An emptypaperless.urlloads, soservecan start and show what is missing: the status strip's Paperless row andsaneless doctorsayThe paperless-ngx address has not been set.No scan starts while it is empty:saneless scanexits 2 before the scanner is opened, with a line endingthe paperless-ngx address in paperless.url has not been set, and the web UI greys out the Scan button and refuses the scan. Should a scan still reach the upload with no address, it fails with a line sayingpaperless.url is not set, or has no http or https scheme. It is not retried, and nothing is copied to the consume folder even when one is configured: the PDF is kept infailed/in the data directory and the line ends with its path. Set the URL, then upload the kept PDF yourself or scan again.
python-sane is not installed (exit 2)
saneless needs python-sane, which in turn needs the SANE library. When it cannot be imported,
scan, devices, auto-profiles and serve each refuse at once, before touching the config or
the scanner. The line gives the import's own reason and names the package to install.
- Install the SANE development package:
libsane-devon Debian or Ubuntu,sane-backends-develon Fedora, RHEL or Rocky. - Reinstall saneless so python-sane is built against it.
saneless jobs and --help on any command do not need python-sane and keep working. See
Install on Bare Metal.
Paperless errors (exit 3)
The line starts with Paperless error:.
- Unreachable. saneless sends the upload again, with a growing pause of at most 5 seconds,
for about 60 seconds while every failure proves the upload cannot have reached paperless-ngx:
the connection is refused or cannot be made in time, no connection is free, a proxy refuses the
tunnel, or sending the file times out. If that goes on for the whole time and a consume
directory is configured, the PDF is saved there instead and the scan exits 6, not 3 -- see
Saved to the consume folder. Without one, the scan
fails, and the line says it could not connect for 60s -- or could not deliver the upload for
60s, when the last attempt had connected and then stalled sending the file, or found no free
connection. An upload that failed after the whole
file was sent, or that got a 5xx, is not this case and is never sent again: it is
exit 9. That includes a paperless-ngx
restart behind a reverse proxy: the proxy answers
502or503while paperless-ngx is down, so the scan ends amber rather than being retried here. Check thatpaperless.urlis reachable from where saneless runs. Ahttps://certificate that this machine does not trust also arrives here, reported as unreachable in both the log and the web UI -- see TLS certificate not trusted below before you go looking at the network. - TLS certificate not trusted. The line names an SSL failure, for example
Paperless error: Could not fetch tags from Paperless at https://paperless.example.com/: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self-signed certificate (_ssl.c:1081), and the scan exits 3 -- but only without a consume directory. A certificate that cannot be verified is classified as unreachable, so the upload is retried for about 60 seconds, and with a consume directory configured the PDF is saved there instead: the scan then endsFALLBACK, shown as Saved to folder, andsaneless scanprintsSaved to folder: <title>on stdout, theNot uploaded: ...line and the warning on stderr, and exits 6 (see Saved to the consume folder). That is the dangerous case rather than the benign one -- every scan still delivers a document, but into a folder that applies none of its title, tags or correspondent, so a TLS misconfiguration can run unnoticed for a long time. Watch for it where each kind of scan reports: forsaneless scan, exit 6 and the stderr lines, which a script should treat as a problem to fix rather than a success; for a web scan, Saved to folder in the status area and the job history (saneless jobslists web scans only, because a CLI scan is not recorded in the job store). The same failure looks different in the web UI. The status strip andGET /api/paperless/testreport a bareunreachablewith no TLS text anywhere, because a certificate that cannot be verified means the connection never established, and saneless classifies that as unreachable -- it is reported as the Unreachable. case above, with the SSL detail dropped. If your web UI says Unreachable, this bullet may be why. The message on the scan path is OpenSSL's own. saneless verifies the certificate against the operating system's trust store, not a certificate bundle inside a Python package, so a private or corporate CA must be trusted by the operating system, or named withSSL_CERT_FILE. There are two fixes. Install the CA into the operating system's trust store, which is the better option wherever it is available -- in the container, copy the certificate to/usr/local/share/ca-certificates/my-ca.crtand runupdate-ca-certificates. Or point OpenSSL at the certificate file directly withSSL_CERT_FILE, described in Environment Variables. If the path you give does not exist, or is a directory rather than a PEM file, saneless refuses at startup withPaperless error: Could not build the TLS trust store for Paperless at <url>: <OS error text>; check SSL_CERT_FILE and SSL_CERT_DIR-- a different error from the certificate-verify failure above, and one that means the remedy itself is misconfigured rather than the certificate being untrusted. Under Docker the usual cause is a bind mount whose host file is missing, which gives the container a directory. Do not turn certificate verification off to make this go away: saneless sends the Paperless API token on every request, and an unverified connection hands that token to anyone in the path. - Malformed or unset URL. This is a configuration error (exit 2), not a Paperless error,
and it is never retried and never saved to the consume folder. See
paperless.urlorpaperless.tokenrefused andpaperless.urlnot set under Configuration errors. - Upload rejected. paperless-ngx answered with a 4xx, such as a bad API token or a field it refuses. The line gives Paperless's own reason. A rejected upload is never retried and never falls back to the consume directory; fix what the reason names and scan again.
- Upload redirected. paperless-ngx, or a proxy in front of it, answered with a redirect. The
line names where the upload was sent. It is not retried and never falls back; set
paperless.urlto the base of that address (often thehttps://form of the same host) and scan again. - paperless-ngx is too old or too new. The line reads
Paperless at <url> does not accept API version 9 or 10; saneless needs paperless-ngx 2.16 or later, and the web UI says "This paperless-ngx does not speak an API version saneless supports (9 or 10)." paperless-ngx answered406: it refuses every API version saneless speaks. saneless needs paperless-ngx 2.16 or later, which speaks version 9, or 10 on 3.x. Upgrade paperless-ngx, then scan again; the status strip andGET /api/paperless/testreportincompatible_versionuntil you do. Nothing was stored, so the kept PDF can be imported or the stack scanned again. - Consume directory missing. The line reads
consume directory <dir> does not exist — is the paperless-ngx volume mounted?. The upload could not get through, and the fallback found no directory atconsume_dir. saneless never creates it, because a directory made where the mount should be is one paperless-ngx never looks at. Mount paperless-ngx's consume volume there, or correctconsume_dir, and import the kept PDF. Two nearby lines name other causes:consume directory <dir> is not a directorymeans a file is in its place, andconsume directory <dir> cannot be read: ...means saneless could not examine the path -- usually a permission on it or a parent -- so the folder may well be there. - A duplicate is not a failure. When paperless-ngx refuses the upload as a duplicate of a document it already holds, the scan ends Uploaded with a warning (exit 7), not here; see Uploaded with a warning.
When the upload fails, the assembled PDF is kept and its path is added to the error. A kept PDF paperless-ngx had already taken is named as such: the failure came while saneless waited for the document to be consumed, or it was the other half of a manual-duplex pair that failed. The line then says the file had already been accepted as a task, or saved to the consume folder, so check paperless-ngx before uploading it, or it will be there twice. If that PDF could not be kept either and its page files were kept instead, the line says the same of them. How Consume Directory Fallback Works explains which failures retry, when the consume directory is used, and where a kept PDF goes.
PDF assembly errors (exit 4)
The line starts with PDF error:. saneless scanned the pages but could not write them as a PDF.
A full disk is not this error: it is exit 10.
- Check that saneless can write to the directory where it writes its working files (
tmp_dirin[output]). - If it can, the PDF library refused one of the scanned images, and the line gives its
reason. Try the scan again with a different
modeorresolutionin the profile.
The scanned pages are not lost when this fails. saneless writes each page to disk as it arrives,
so when assembly is what failed it moves those page files into a job-keyed directory under
failed/ in its data directory and names that directory in the error. The pages are ordinary PNG
files, one per sheet, named a-0001.png, a-0002.png, ... in the order the first pass fed them,
and b-0001.png, ... for a second pass. Fix the cause and scan again, or assemble them yourself if
rescanning the document is not practical.
If it was a manual duplex job, the file names are not the page order. You turned the stack over
between the passes, so the backs came back in reverse: the document is a-0001, b-000N,
a-0002, b-000N-1, and so on, with the last b- file behind the first a- file. Sorting the
directory by name would put every front page first and every back page last, in the wrong order.
A simplex scan has only a- files and sorts correctly.
Saved to the consume folder (exit 6)
stdout reads Saved to folder: <title>, and stderr reads Not uploaded: saved to the consume
folder without its title, tags or correspondent, followed by the warning, which names where the
PDF was written.
The document was delivered, so do not scan the stack again. saneless could not reach paperless-ngx through its API, even after retrying for about 60 seconds, and a consume directory is configured, so it wrote the PDF there instead. paperless-ngx picks the file up from that folder and applies its own matching rules to it, not the title, tags and correspondent chosen for this scan.
- In paperless-ngx, find the new document and set its title, tags and correspondent by hand.
- Then find out why the API upload failed: it is the Unreachable. or TLS certificate not trusted. case under Paperless errors, and every scan will keep going to the folder until it is fixed.
Uploaded with a warning (exit 7)
stdout reads Uploaded with a warning: <title>, and the warning itself is on stderr. The document
reached paperless-ngx with its title, tags and correspondent, so do not scan the whole stack
again. The warning is one of these:
- paperless-ngx already holds this file as document #N. paperless-ngx refused the upload as a
duplicate: it already has this exact file, as the document the warning names, so the scan is not
lost and nothing is kept in
failed/. The warning goes on "it was not stored again, and this scan's title and tags were not applied to it", and adds that the document is in paperless-ngx's trash when it is; restore it from there if you still want it. paperless-ngx 2.x always refuses a duplicate, and 3.x does so only whenPAPERLESS_CONSUMER_DELETE_DUPLICATESis enabled (it otherwise stores a second document). In a manual duplex scan uploaded as two halves, the warning names the half. Set the title and tags on the existing document by hand if you need them. - Tag N no longer exists in paperless-ngx and was not applied. A tag or correspondent chosen
for the scan, or a profile default, was not in paperless-ngx's lists, even after asking again,
so the document was filed without it. The warning names every id it dropped. Pick another in
the form, or remove the id from the profile's
default_tagsordefault_correspondent. A tag the API token's user is not allowed to see counts as missing too; give that user permission to view it if it should apply. - Pages could not be read by the scanner and were skipped. The warning gives the count. Those sheets are missing from the document in paperless-ngx; open it, find the gaps, and scan just those sheets.
- Page count mismatch. A manual duplex scan got a different number of fronts from backs, so
saneless could not interleave them. It uploaded the fronts and the backs as two separate
documents, with
(fronts)and(backs)after the title. In paperless-ngx, check both documents and look for a sheet that fed twice or not at all. -
The scanner could not read N sheet(s), so the fronts and backs could not be paired reliably. In a manual duplex scan, one of the passes skipped a sheet it could not read. A skipped sheet moves every later page of that pass by one, so saneless does not interleave the passes even when the two counts agree. It uploaded the fronts and the backs as two separate documents, with
(fronts)and(backs)after the title, and the warning gives the number of sheets. The(backs)document is in sheet order, the same order as(fronts), not the reversed order the second pass fed them in. In paperless-ngx, find the sheets missing from either document and scan them again, or scan the whole stack again and delete both documents. -
Finished after N pages because nobody answered. A multi-page scan waited
operator_wait_timeout_secondsfor an answer and nobody gave one, so saneless finished the document with the pages it had. The warning says whether the question was about the next page or about blank pages; in the second case, those blank pages were left out. Open the document and scan whatever is missing as a new document. - Finished at N pages: no new scan starts once a document has 500 pages. A multi-page document reached the page limit, so saneless finished it. Scan any remaining pages as a new document.
- Finished at N pages: one scan stops after 500 sheets, so sheet 501 was fed but not kept. One scan through the feeder keeps at most 500 sheets. A feeder can only tell that the stack goes on by feeding one more sheet, so sheet 501 went through the feeder and was thrown away. The pages before it were uploaded. Take sheet 501 and everything after it from the output tray and the feeder, and scan them as a new document. N counts the pages uploaded, after any blank pages were removed. In a multi-page scan the document is finished at that scan, and the warning counts the document's pages.
- Finished at N pages: the scan of the backs stops after 500 sheets, so sheet 501 of the turned-over stack was fed but not kept. The backs pass of a manual duplex scan reached its cap. The fronts pass ended on its own with fewer sheets, so the turned-over stack held sheets whose fronts were never scanned. The fronts and backs were uploaded as two documents, and N counts the pages of both. Check both documents, and scan any sheet missing from either again, both sides, as a new document.
- Finished at N pages: a scan from an Auto source through the feeder stops after 50 sheets, so
sheet 51 was fed but not kept. A profile whose
sourceis the scanner's Auto source, withauto_source_mode = "adf", keeps at most 50 sheets per scan, because a scanner that has no paper in its feeder may scan its glass again and again as if it were. The warning goes on: "If the feeder was already empty, the scanner was scanning its glass again; set auto_source_mode = "flatbed" for this profile. Otherwise scan sheet 51 and any remaining pages as a new document." If you fed fewer than 51 sheets, delete the document, which is the glass scanned over and over, and setauto_source_mode = "flatbed". - The scanner has no source named 'Flatbed', so its Auto source was scanned through the
feeder. The profile asked for a flatbed source the scanner does not list, the scanner's Auto
source stood in for it, and because the profile's
auto_source_modeis"adf", Auto scanned through the feeder rather than the glass. Check that the document is what you meant to scan, then set the profile'ssourceto one of the names the scanner lists (see Configure Scan Profiles). When Auto stays on the glass, no warning is given, because the scan did what the profile asked. - The backs were not scanned: sheet N is already in the output tray. A manual duplex scan reached its sheet cap on the fronts pass, so saneless uploaded the fronts it kept, as one document, and did not ask you to flip the stack: the sheet it fed but did not keep would have paired every back with the wrong front. The warning before it names that sheet. Scan the backs of the uploaded sheets, and the remaining sheets, as new documents. See When a pass reaches its sheet cap.
- The scan of the backs stopped at its sheet cap, so the fronts and backs could not be paired
reliably. A manual duplex scan reached its sheet cap on the backs pass. The fronts and backs
were uploaded as two documents,
(fronts)and(backs), even when the counts agree, because the backs pass fed a sheet the fronts pass never did. The warning goes on to name the sheet that was fed but not kept.
A run that was saved to the consume folder and carries a warning exits 6, not 7: the missing title, tags and correspondent are the larger problem.
Every page looked blank (exit 8)
The line starts with Empty-page detection:. The scanner worked: it returned pages, and
empty-page detection judged every one of them blank, so nothing was uploaded. The scanner is not
the thing to check.
The pages are not lost. saneless assembles every page it scanned, before detection removed any,
into a PDF under failed/ in its data directory, and the line names the path. If that PDF cannot
be built -- the disk is short of room, say -- the page files are kept there instead, and the line
names their directory. Open what was kept:
- If the pages really are blank, there is nothing to do. Delete the file.
- If they are not blank -- faint pencil, light print or a mostly empty form -- detection was too
eager for this document. Lower
empty_page_coverage_thresholdfor the profile, or turn detection off for it withenable_empty_page_detection = false, then scan again. Or keep the preserved PDF and upload it yourself.
A multi-page scan fails the same way, with exit 8, when a question times out while the document holds no page because every page so far was skipped as blank. The skipped pages are what is kept.
When Every Page Is Blank explains how detection decides.
The document may already be in paperless-ngx (exit 9)
The line starts with Paperless error:, but this is not a failed upload. saneless cannot tell
whether paperless-ngx has the document, so scanning the stack again could store it twice. Do not
rescan until you have checked. A script should treat 9 the same way: never rescan on it.
It means one of two things, and the error says which:
- The upload may have reached paperless-ngx. saneless sent the whole document, and then the connection dropped or timed out before paperless-ngx answered. The document may have arrived. saneless does not send it again and does not save it to the consume folder, because either could make a second copy.
- paperless-ngx received the document but did not confirm filing it. paperless-ngx accepted
the upload, and then its processing task did not finish within
paperless_task_timeout, or it failed for a reason other than being a duplicate. A long document with OCR can take longer than the timeout, and paperless-ngx may still be working on it.
To check, open paperless-ngx's document list and sort it by the date added. Look for the scan's title, or for a document with its pages. When paperless-ngx received the document, give it a few minutes to finish before you decide it is not there.
- If the document is in paperless-ngx, there is nothing to do. Delete the copy in
failed/. - If it is not, a copy is normally kept in
failed/in saneless's data directory, and the line names it. Import that copy into paperless-ngx yourself, or scan the stack again. Import it only if the document is not in paperless-ngx: the copy is the same document, and importing it next to one that arrived makes a duplicate. If the line names no copy, none was kept -- saneless restarted during the upload and found no PDF to keep, or the copy could not be written -- so scan the stack again.
Out of disk space (exit 10)
The line starts with Disk space:. The server ran out of room while scanning, while writing a
page, or while assembling the PDF. The scanner and the pages are fine, so neither is the thing to
check.
The line names the folder that is full. When saneless found the shortfall before writing -- the
checks before a scan, before each page and before assembling the PDF -- it also names how much
space the scan needs. When the disk refused a write partway through, it names only the folder and
the system's reason (No space left on device, or a disk quota). Free space on
the filesystem holding the folder, or point the folder at a filesystem with room: tmp_dir for
the scan in progress, or data_dir for the job database and failed/. Then scan again.
saneless keeps min_free_space_mb (500 MB by default) free for assembling the PDF. It checks that
reserve before a scan starts and again before each page is written, so a scan that would fill the
disk stops early with this exit code instead of failing halfway through. Lower the setting only
if the server really has less room to give; assembling a PDF needs about twice the size of the
scanned pages on top of it. If the scan had pages when it stopped, the line says whether and where
they were kept.
Interrupted by a signal (exit 129 and 143)
The line starts with Interrupted:. Something outside saneless stopped the command while it ran:
- 129 is SIGHUP: the terminal or SSH session running the command went away.
- 143 is SIGTERM:
kill, a service manager or a container runtime stopped the command.
Each code is 128 plus the signal number, the shell's convention. Nobody chose to stop the scan, so
it is not treated as a cancel: the pages already scanned are kept, normally as a PDF, under
failed/ in the data directory, and the line names the path. A line that names no path kept
nothing, because there was nothing to keep: the command was not a scan, or the scan was stopped
before its first page. A saneless scan --multi-page run waiting for your answer counts too: the
pages kept so far are saved, not uploaded. Scan the rest of the stack, or the whole stack again,
and delete or upload the kept file yourself. The exceptions are a signal that arrives while
saneless waits for paperless-ngx to consume a document it has already accepted, and one that
arrives while the document is being sent: the line then says the kept file had already been
accepted, and names the task, or that it was being sent and may have arrived. Either way, check
paperless-ngx before uploading it, or it will be there twice.
A signal that arrives once the scan's outcome is settled -- the document already delivered, or a failure's pages already being kept -- does not interrupt it. The command finishes what it was doing and exits with that outcome's own code, so a delivered scan still exits 0 and a scanner fault still exits 1, with its line naming what was kept. After a hangup the terminal is gone, so those closing lines cannot be printed; they are logged at INFO instead, and whatever could not be printed is discarded as the command exits, so the exit code still stands. The same holds when the output goes to a pipe that was closed early.
Ctrl-C is different. It is a deliberate cancel, exits 130 and keeps nothing (see
Cancelled scans). That holds even when the scan had already failed and
saneless was still moving its pages into failed/: pressing Ctrl-C then stops the move, and
whatever had not reached failed/ yet is lost, so let a failed scan finish reporting first. To run a long scan over SSH without a dropped
connection interrupting it, start it under tmux or screen, or with nohup: a signal the
command was started with ignored stays ignored, so under nohup a hangup does not interrupt it. Once saneless serve
is running, SIGTERM is a graceful stop that exits 0.
The output was cut off (exit 141)
Exit 141 is 128 plus SIGPIPE, the shell's code for a broken pipe. The program reading the output
of saneless devices, jobs, auto-profiles or doctor stopped before the command finished
writing, as head does in saneless jobs | head once it has its lines. Nothing went wrong, so
saneless prints nothing about it and keeps no traceback. A shell reports a pipeline's last
command's status, so you see 141 only with set -o pipefail. If you wanted the whole output, run
the command without the reader that stops early.
saneless scan never exits 141. Its progress and closing lines are not what the scan is for, so a
reader that went away does not change its exit code: a delivered scan still exits 0.
A scan stopped by a crash or a power cut
Some stops leave saneless no chance to react: kill -9 (SIGKILL), the out-of-memory killer, a
container killed after its grace period, or a power cut. The command prints nothing and exits with
no code of its own, and the pages scanned so far are left in the scan's working directory under
tmp_dir.
They are recovered the next time saneless starts: when saneless serve starts, or before the next
saneless scan opens the scanner, whichever comes first.
- The pages become a PDF under
failed/in the data directory, the same PDF a failed scan keeps:(partial)for a one-sided scan, or(fronts)and(backs)for manual duplex. A page that was only half written when the process died is left out. If no PDF can be built, for example because the disk is short of space, the page files themselves are moved into a folder underfailed/instead. - A warning in the log names the job, its title and the path of what was kept.
- In the web UI, the job shows as failed with "The server restarted before this scan finished",
followed by where its pages were kept. Only the browser that started the scan sees the path. A
scan started with
saneless scanhas no job in the web UI, so the log warning is where to look. - A web job that was already uploading shows as "May be in paperless-ngx" instead, with "The server restarted while this scan was being uploaded; it may have reached paperless-ngx". Check paperless-ngx's document list before scanning it again.
- A web job that was waiting for someone -- at the flip prompt, or at a multi-page question -- is
marked failed the same way at the next start of
saneless serve, so the page stops waiting for an answer that can no longer arrive.
Nothing recovered is uploaded. Check the kept file, then upload it yourself or scan the stack again, and delete it once the document is in paperless-ngx.
A scan still running is never touched, even by a saneless scan started beside it or by a server
sharing the same tmp_dir. Recovery takes only saneless's own job-* scratch directories whose
scan has ended; anything else in tmp_dir is left alone.
Cancelled scans (exit 130)
Exit 130 means the scan was stopped on purpose, not that something broke:
- You answered no, pressed Ctrl-D or pressed Ctrl-C at the manual duplex flip prompt.
- You aborted a multi-page scan: Abort scan in the web UI, a confirmed
a, or Ctrl-D or Ctrl-C at asaneless scan --multi-pagequestion. Ctrl-C and Ctrl-D do not ask to confirm, however many pages were kept; pressfto keep them. - You pressed Ctrl-C while a one-shot command (
scan,devices,auto-profiles,jobs) was running, or whileservewas still starting up.
Nothing is uploaded, and nothing is kept in failed/ either. A failure keeps whatever it can,
because you cannot get those sheets back without feeding them again; a cancel keeps nothing,
because you chose to stop and saneless would only be leaving you files to delete. In the web UI, a
scan cancelled with Abort scan at the flip step or at a multi-page question is shown as
Cancelled, in grey rather than as an error. A flip wait that times out is not a cancel: it
fails with exit 1. A multi-page question that times out is not a cancel either: it finishes the
document with the pages kept (exit 7). Ctrl-C on saneless serve once the web server is running is a normal stop and
exits 0.
Unexpected errors (exit 5)
Exit 5 means saneless hit an error it did not anticipate: a bug in saneless, not a problem with your setup. Setup problems exit 2.
The line starts with Unexpected error and names the exception type. The full traceback is in
the log file, which the line names. If the line names no log file (the error happened before
logging started, or the log file could not be opened), it ends with a hint instead: run the
command again with -v to see the traceback on stderr.
saneless serve is the exception: it writes no log file, so the traceback is already on its
stream, printed directly above the line, and no hint is offered. Collect it from docker logs
or journalctl instead of restarting the service.
Please report it as a bug and attach the log file. Attach the log only, never your config file,
which holds your Paperless API token. saneless keeps the HTTP libraries' own debug output out of
the log whatever log_level says, because it can include the authorization header.