An unintentional input is something that turns out to change a build's output although nobody meant it to. The current time is the classic example. Others are the directory name, the account name, the CPU type and the compiler version. Finding and removing them is the work of making a build repeatable.
Definitions from the Go team
The Go blog post on reproducible toolchains gives tidy vocabulary. A relevant input is any piece of information the output can change with. A build is reproducible if it can be repeated with all the same relevant inputs. An input is unintentional when it is relevant but was not meant to be.
The post calls the current time the most common unintentional input. When a build writes an executable to disk, the filesystem records the current time as its modification time. If the build then packages the file with tar or zip, that time goes into the archive. Most programs do not let you supply the time as an input, so the build cannot be repeated.
It also lists common relevant inputs:
- the source version and the dependency versions,
- the operating system, which can affect path names,
- the CPU architecture, which can affect optimisations or data layout,
- the compiler version and options,
- the name of the directory containing the source, which may appear in debug information,
- the user name, group name, uid and gid, which may appear in archive metadata.
Two levels of success
The post separates two goals. A build is reproducible when every relevant input is configurable and documented. A build is easy to reproduce when you eliminate inputs instead of documenting them. It calls a build perfectly reproducible when its sole relevant input is the source code.
Go 1.21.0 was the first Go toolchain the team describes as perfectly reproducible. That claim is about the Go toolchain build, not about your application, but the method applies to your build too.
Examples of inputs that were removed
The post describes several, and they map to everyday problems.
| Unintentional input | How it showed up | The fix |
|---|---|---|
| Randomness from map iteration and goroutine ordering | Output order varied | Sort the items before generating output |
| A library choosing among equal outputs | Sort of equal elements, compression output changed between versions | Copy the specific packages into the source tree used by the bootstrap compiler |
| The host C toolchain | Precompiled packages depended on the local C compiler | Stop shipping the precompiled package; compile it locally on first use |
You do not need to copy a compiler to apply the idea. Ask of each step in your build: where does this value come from, and would it be the same on another machine tomorrow?
A hunt for your own inputs
- List what your build reads: files, environment variables, the clock, network resources, installed tools, the username and the path.
- For each item, decide: is it part of the source, a pinned dependency, or an accident?
- Remove accidents. Fix timestamps, sort ordered data, remap paths, pin tools, set the timezone and locale.
- Rebuild in a different directory, as a different user, on a different machine, and compare checksums.
- Use diffoscope on any mismatch.
Related fixes are covered in timezone and locale settings and unstable ordering.
Try it yourself
Click through the demo and look at the dependency list, which is one set of inputs you can declare and review.
Click through it at your own pace, or open it full screen.
Quick check
Is every input bad?
No. The source code and pinned dependencies are intended inputs. The problem is inputs nobody listed.
What is the difference between reproducible and perfectly reproducible?
Reproducible means you can repeat the build if you recreate every input. Perfectly reproducible means the source is the sole input.
Safeguard's SBOM and dependency scanning, generally available, helps with one class of input, your declared dependencies. The free scan at gold.safeguard.sh/scan can list them.
Sources
Last reviewed: 19 October 2026.