Skip to content

Exit and diagnostic codes

kivyforge reports a failure in two ways that a script can branch on: the process exit code, and, with --json, diagnostics that each carry a stable KF-* code. The codes are a contract. The human-readable messages can change in any release, so never match on them.

Both tables on this page are generated from kivyforge's source. To read the same vocabularies at run time, run kivyforge capabilities --json.

Exit codes

Branch on the exit code first. It tells you the kind of failure without parsing any text.

Code Meaning Typical reaction
0 success Continue.
1 config or user error Fix pyproject.toml and retry.
2 usage error (click) Fix the command line. This is click's usage error; kivyforge never raises it deliberately.
3 environment or toolchain missing Install the missing tool, then retry the same command.
4 lock file out of date Re-lock with kivyforge lock -p <platform>.
5 build failed Read the build log on stderr; the toolchain ran and reported an error.

Exit code 2 belongs to the command-line parser: it means a mistyped flag or argument. kivyforge never uses 2 for its own failures, so a usage error stays distinct from a missing toolchain.

Diagnostic codes

With --json, each entry in the envelope's diagnostics array has a code, severity, and message, and optionally remediation and context. See JSON output for the full shape. A diagnostic on an ok: true run is a warning, not a failure.

Code Severity Meaning Remediation
KF-ANDROID-APP-CONFLICT error Android: app_dir has its own android.py or android/, which the bundled android package would shadow. Rename or remove it; context names the path.
KF-ANDROID-DEPENDENCY-CONFLICT error Android: a dependency provides its own android module. kivyforge bundles an android package, which would shadow it. Remove the dependency, or add it to [tool.kivy.android].exclude if another package pulls it in; context names the distribution.
KF-ANDROID-INCLUDE-OVERRIDE info Android: an include_files file replaced one kivyforge generates, such as res/values/styles.xml or the launcher icon. The build goes on. None if the override is deliberate; context names the path.
KF-ANDROID-NATIVE-LIB-MISALIGNED error Android: the built APK or AAB holds a native library the device cannot load, because a segment's file offset and address disagree. Usually the strip during packaging damaged a library patchelf had edited. Set strip_native_libs = false and report the wheel; context names the library.
KF-ANDROID-WHEEL-ARCH error Android: a native library is built for another architecture than the ABI its wheel is tagged for, so it would fail to load on the device. Report it to the wheel's publisher and lock a correct wheel; context names the library, its distribution and the abi.
KF-ANDROID-WHEEL-LAYOUT error Android: locked wheels ship their native libraries under opt/lib, Chaquopy's layout for separate library wheels, which Flet's index serves. kivyforge cannot load libraries from there. Lock the package that requires them from an index whose wheels carry their own libraries; context names the distributions.
KF-ANDROID-WHEEL-SUFFIX error Android: an extension module is named with a suffix CPython on Android does not import, such as a build host's or another Python version's. Report it to the wheel's publisher and lock a correct wheel; context names the library, its distribution and the abi.
KF-ARTIFACT-MISSING error A build tool reported success but the product is not where it should be. Read the build log; this usually points at a broken toolchain step.
KF-BUILD-TOOL-FAILED error A build tool (Gradle, xcodebuild, appimagetool) ran and exited non-zero. Read the build log on stderr; context names the tool and task.
KF-BYTECOMPILE-NO-INTERP warning byte_compile is on but no compatible host interpreter was found, so source shipped instead. Install a CPython matching the target's minor version, or set byte_compile = false.
KF-DEPENDENCY-DRIFT warning An installed dependency sits outside the specifier pyproject.toml declares. Align the installed version, or widen the specifier. Nothing was modified.
KF-DOCTOR-CHECK warning A doctor check reported WARN or FAIL and has no specific code yet. See data.checks, keyed by the check name.
KF-ENTITLEMENTS-UNGRANTED warning Retired: no longer emitted. It warned that a profile pinned under iOS automatic signing lacked a declared entitlement; Xcode refuses any pin under automatic signing, so that build now fails before xcodebuild. None. The code stays reserved and will not be reused.
KF-ERROR error An expected failure with no more specific code assigned yet. Read the diagnostic's message and remediation.
KF-HOST-INCAPABLE error This host cannot build this target at all (for example iOS from Windows). Build on a supported host; see the host matrix.
KF-IDE-NOT-FOUND warning open found no IDE launcher on PATH. The project exists and can be opened by hand. Install the platform IDE, or open the generated project manually.
KF-LOCK-DRIFT error The committed lock no longer matches pyproject.toml. Run kivyforge lock -p <platform>.
KF-LOCK-INCOMPLETE error The lock matches pyproject.toml but predates something kivyforge now adds to it (Android: pyjnius, which Kivy needs at launch). Re-lock with kivyforge lock -p <platform> --update.
KF-LOCK-MISSING error No pylock.<platform>.toml exists for the target. Run kivyforge lock -p <platform>.
KF-LOCK-UNREADABLE error A lock exists but could not be parsed (a bad merge or a truncated write). Re-create it with kivyforge lock -p <platform>.
KF-LOCK-WARNING warning Resolution made a judgement call worth surfacing. The lock is usable and the run is ok. Read the note; no action is required unless it surprises you.
KF-MANIFEST-POLICY info The Android release-manifest policy passed with an informational finding. Review the finding; no action is required.
KF-METADATA-ENTRY-POINTS-OUTSIDE-PROJECT error A setuptools project declares entry points in setup.cfg or setup.py and none in [project], where kivyforge reads them to write the app's package metadata. Exit 1; context names the path. Move them into [project.entry-points] (console scripts into [project.scripts], GUI scripts into [project.gui-scripts]).
KF-METADATA-NOT-GENERATED warning [project].dynamic lists entry-points, scripts or gui-scripts, so kivyforge writes no package metadata for the app. context: reason (dynamic or static-and-dynamic) and fallback, the development egg-info that ships instead, or none. Declare the entry points statically in [project]; until then, run pip install -e . before each build.
KF-PATH-DEPTH warning A Windows onedir bundle nests so deep it only runs from a short folder while long paths are off (the Windows default). The artifact is fine; where it is unpacked is the constraint. Install to a short folder, or enable long paths on the target machines.
KF-SIGNING-UNCONFIGURED warning The package shipped unsigned or ad-hoc signed where real signing is available. Configure signing for the platform, or ship unsigned deliberately.
KF-TOOLCHAIN-MISSING error A required tool is not installed. Install the named tool and retry.
KF-TOOLCHAIN-UNUSABLE error A tool is present but could not be executed. Fix the file's permissions or executability; context.errno says why.
KF-VERSION-APPLE-FORMAT error or warning The version is not one to three dot-separated numbers, which App Store Connect refuses (ITMS-90060). An error for an iOS app-store export, a warning for other iOS exports and macOS package. Build from a release tag, pass --app-version 1.2.3, or export with --export-method ad-hoc or development.
KF-VERSION-FILE-NOT-REFRESHED warning setuptools-scm's version_file was not rewritten, because the version came from --app-version or pyproject.toml. Pin with SETUPTOOLS_SCM_PRETEND_VERSION instead of --app-version.
KF-VERSION-ISOLATION-UNUSED info --no-build-isolation had no effect: the version is static, so the build backend did not run. Nothing to do; drop the flag for this project.
KF-VERSION-UNRESOLVED error pip could not produce the dynamic [project].version: the build backend failed (not a git checkout, no tags) or the package index was unreachable. Check pip wheel --no-deps . works; in CI fetch tags (fetch-depth: 0); or pass --app-version.

What's next