Troubleshooting
What each failure means, what to check, and the safe next step.
Start with the exit code
Every command exits with one of six codes, and the code narrows the problem before you read anything else.
0 success 1 validation error the file is well-formed but breaks a rule 2 structure invalid the workspace does not match the specification 3 drift detected the specification changed since .orv.lock 4 file error missing, empty or unparseable file 5 internal error a defect in the engine
One case does not come from the engine at all. A command invoked without a required argument — orvienm verify, orvienm new orvienm init with nothing after it — is rejected by the argument parser, which prints usage: and the missing argument by name, then exits 2 as command-line tools conventionally do. It is a usage error, not a statement about a workspace: read the first line of the output to tell the two apart.
Two commands report by default rather than failing: policy doctor both exit 0 while printing what they found. Pass --strict to either one to turn the same finding into exit 2. Detection is identical in both modes — only the exit code changes — so a step you add to a pipeline cannot start failing it until you ask.
Reading the file
File not found: structure.yaml
exit: 4
- Meaning
- The path given to the command does not exist. Nothing was read and nothing was changed.
- What to check
- The engine's default filename is .orvienm.yaml, not structure.yaml or example.yaml. Confirm the file name and that you are in the directory you think you are.
- Next step
- Pass the correct path, or omit the argument on plan, apply, graph and policy to let the engine find .orvienm.yaml, orvienm.yaml or orvienm.yml.
Error: Invalid YAML format: mapping values are not allowed here
exit: 4
- Meaning
- The file could not be parsed as YAML. This happens before any Orvienm rule is applied, so the message comes from the YAML parser and includes the line and column.
- What to check
- Indentation, a missing colon, an unclosed bracket or a tab character where spaces are expected.
- Next step
- Fix the syntax at the reported line, then run validate again.
Error: YAML file is empty. / Root YAML structure must be a dictionary.
exit: 4
- Meaning
- The file parsed, but its top level is not a mapping — it is empty, or it is a list or a bare scalar.
- What to check
- That the file starts with keys such as version: and structure:.
- Next step
- Start from the minimal file in the Specification Reference.
Validation errors
Validation collects every problem and reports them together, one per line, under a Validation failed: header. Messages name the field and the fault; they do not carry line numbers, so locate the field by name.
Unknown field at root level: 'relationships'.
exit: 1
- Meaning
- The root key set is closed. Only version, structure, style and policy are accepted, and anything else is rejected rather than ignored.
- What to check
- Keys carried over from older drafts or from another tool. relationships, requires, profiles and appendix are all rejected.
- Next step
- Remove the key. If you need what it expressed, it is not implemented in this Alpha.
Missing required field 'version'. / Missing required field 'structure'. / Missing required field 'structure.name'.
exit: 1
- Meaning
- A required key is absent.
- What to check
- version and structure at the root; name and directories inside structure.
- Next step
- Add the missing key. Validation reports every problem at once, so one run tells you all of them.
'structure.directories' must be a list. / 'structure.directories' cannot be empty.
exit: 1
- Meaning
- directories is present but is not a non-empty YAML list. A common cause is writing it as a nested mapping.
- What to check
- That each directory is a list item under directories:, not an indented key.
- Next step
- Convert nested mappings to a flat list. Nested mapping syntax is not supported.
Directory '/data' cannot be an absolute path.
exit: 1
- Meaning
- Entries must be relative. A specification is not allowed to reach outside the workspace.
- What to check
- Leading slashes, and Windows drive letters such as C:\data.
- Next step
- Express the path relative to structure.name.
Directory '../up' cannot contain path traversal ('..').
exit: 1
- Meaning
- Traversal is rejected, for the same containment reason.
- What to check
- Any .. segment anywhere in the entry.
- Next step
- If the directory genuinely belongs elsewhere, it belongs to a different specification.
Duplicate directory paths are not allowed.
exit: 1
- Meaning
- Two entries normalise to the same path. They do not have to look identical — a and ./a collide, as do docs and docs/.
- What to check
- Entries that differ only by a ./ prefix, a trailing slash or separator style.
- Next step
- Remove one of them.
Directory name 'a:b' contains invalid character ':'.
exit: 1
- Meaning
- The characters < > : " \ | ? * are rejected in directory entries. Forward slashes are allowed.
- What to check
- Colons in particular, which YAML also treats specially.
- Next step
- Rename the directory.
Planning, applying and verifying
Drift detected — Current YAML fingerprint differs from .orv.lock.
exit: 3
- Meaning
- Apply is drift-gated. The specification has changed since the lock file was written, so apply refuses to run. Nothing was modified.
- What to check
- Whether the change to the specification is intended. Note that drift here means the file changed, not the filesystem — editing version, style, structure.name or the directory list all change the fingerprint.
- Next step
- If the change is intended, delete .orv.lock and apply again; apply creates whatever the change added, keeps everything already there, and a new lock is written. Removing the lock accepts every edit in the file at once, so read the specification first. To preview without touching the gate, use apply --dry-run.
Plan prints '? undeclared build/' and a non-zero Undeclared count.
exit: 0
- Meaning
- Plan found a directory the specification does not declare. It is reporting, not scheduling: apply contains no deletion path and will not remove it.
- What to check
- Whether the directory should be declared. Build output, virtual environments and scratch directories commonly appear here.
- Next step
- Add it to directories if it belongs to the structure, or leave it — it is safe either way. Nothing removes it.
A directory added to the specification was not created by apply.
exit: 3
- Meaning
- Apply grows an existing structure, so a newly declared directory is created normally. What stops it is the drift gate: editing the specification changed its fingerprint, so apply exited 3 without touching anything. Plan still reports '+ create' for the entry because plan is read-only and is not gated.
- What to check
- Whether apply printed 'Drift detected' and exited 3 rather than reporting the structure as compliant.
- Next step
- If the change is intended, delete .orv.lock and apply again. Apply then creates the new directory, keeps everything already there, and writes a new lock. Earlier Alpha builds could not do this at all — apply exited 2 with 'Existing structure is INVALID' even after the lock was removed.
Apply exits 2 with 'Error while creating structure'.
exit: 2
- Meaning
- A file already occupies a path the specification declares as a directory — either a declared entry or an intermediate a nested entry implies. Apply checks for this before it touches disk, so nothing at all was created: no partial tree is left behind.
- What to check
- The paths listed under 'A file already occupies a path the specification declares as a directory'. Each one is a file standing where a directory is declared.
- Next step
- Rename or move the file, then apply again. Apply never opens, overwrites or removes it — your file is left byte for byte as it was.
Doctor reports CRITICAL with orphan directories after a successful apply.
exit: 0 · 2 with --strict
- Meaning
- The workspace contains directories the specification does not declare. Intermediate directories created for a nested entry are not counted here — they are part of the declared structure.
- What to check
- The orphan_directories list under doctor --json. Build output and scratch directories are the usual cause.
- Next step
- Declare them if they belong to the structure, or accept the report: nothing removes them.
Verify prints Status: INVALID and exits 2.
exit: 2
- Meaning
- A declared directory — or one implied by a nested entry — is missing from the workspace. A regular file standing at a declared path counts as missing too: a declared directory is satisfied only by a directory. Verify is a read-only check and changed nothing.
- What to check
- The list of missing directories printed beneath the status line.
- Next step
- Apply the structure, or correct the specification if the directory should not be declared. Verify's exit code can be used directly as a pipeline gate.
Status reports Lock file: NOT FOUND after applying.
exit: 2
- Meaning
- A successful apply records the lock whether it created the structure, grew it, or found it already compliant. NOT FOUND after applying therefore means the apply never reached that point.
- What to check
- Whether the run was a --dry-run, or whether apply was blocked by the drift gate or failed. None of those write a lock.
- Next step
- Run apply without --dry-run and confirm it exits 0; the lock is written on the same run.
Policy reports a violation but the command still succeeds.
exit: 0
- Meaning
- The policy command reports by default: it prints the violation and exits 0, so adding a policy block cannot fail a pipeline that was green the day before. --strict is the opt-in that turns the same finding into exit 2.
- What to check
- The printed violation list, which gives each path relative to the structure root.
- Next step
- Accept the report, or pass --strict to gate on it. doctor --strict, status and verify also exit 2 on a structural problem.
UnicodeEncodeError: 'charmap' codec can't encode character
exit: 5
- Meaning
- A Windows console using a legacy code page cannot render the status glyphs the CLI prints.
- What to check
- Whether the terminal is running in an encoding other than UTF-8.
- Next step
- Set PYTHONIOENCODING=utf-8 in the environment, or run the command in a UTF-8 terminal.
If none of these match
Confirm the specification first with orvienm validate .orvienm.yaml, then inspect the workspace with orvienm doctor .orvienm.yaml --json, which reports the root, missing directories, undeclared directories, lock presence and fingerprint state in one object.
The Specification Reference lists every accepted key and rule, and the CLI Reference gives each command's exact behaviour and exit codes.