Errors & Troubleshooting
A reference of the error messages gogo emits, what triggers each one, and how to fix it. Errors are grouped by the layer that surfaces them — discovery, parsing, validation, resolution, and execution.
Discovery
no gogo.yaml found
You ran gogo from a directory that has no gogo.yaml and no ancestor with one either. gogo walks up from the current working directory and stops at the nearest gogo.yaml; if it reaches / without finding one, you get this error.
Fix: create a gogo.yaml at the project root, or cd into a directory that has one above it.
When no gogo.yaml is found gogo also looks for foreign task files — in the
current directory only, never in ancestors (running gogo inside an
untrusted checkout must not execute someone else’s task file from a parent
directory):
Taskfile.yml/taskfile.yml/Taskfile.yaml/taskfile.yaml→ shells out totask.mise.toml→ shells out tomise run.Makefile/makefile/GNUmakefile→ shells out tomake.
If the matching binary isn’t on PATH the runner is silently skipped (so a
stray Taskfile doesn’t break unrelated invocations when task isn’t
installed).
no gogo.yaml found in <dir>
Variant of the above when an explicit directory was checked.
Parsing
parsing <path>: …
The YAML failed to parse. The line/column shown comes from the YAML library and points at the offending token.
Fix: validate the file with any YAML linter; the most common cause is mixed tabs/spaces or an unquoted value containing :.
task name <X> must not contain '/' or '\'
Task names may not contain path separators. They’re only allowed in namespace prefixes, which gogo synthesizes from includes: directory names.
task name <X> must not contain '..'
Same family — task names are checked against a small allow-list to keep namespace resolution unambiguous.
task name must not be empty
Empty key in a tasks: map. Usually a stray - or quoting mistake.
Includes & flatten
include <X> must be a subdirectory (absolute paths are not allowed)
include <X> must be a subdirectory (path separators are not allowed)
include <X> must be a subdirectory ('..' is not allowed)
includes: entries are directory names, not paths. They must point to a direct subdirectory of the current task file. For multi-level layouts, chain includes — a top-level gogo.yaml includes frontend/, whose frontend/gogo.yaml includes web/, and so on.
cyclic include <X> detected in <file>
cyclic flatten <X> detected in <file>
A → B → A. gogo detects cycles by absolute directory (for includes:) or absolute file path (for flatten:).
Fix: break the cycle. Common cause: a flatten: file pulling itself in transitively through a shared helper.
resolving include <X> from <file>: …
loading include <X> from <file>: …
The path resolved but the include couldn’t be loaded — either it doesn’t exist on disk or the included gogo.yaml itself failed to parse. The wrapped error has the underlying cause.
Defaults & secrets validation
top-level default: <X> does not reference any defined task
Your file declared default: build (or similar) but no task named build exists. Namespaced names are accepted (default: backend:build).
task <T> references unknown secret <S>; declare it under top-level secrets:
The task lists a secret name that has no entry in the top-level secrets: map. This is load-time validation — you don’t have to run the task to see it.
secret <S> has unknown backend in <URI> (supported: op://)
Only op:// is supported today. Other URI schemes are rejected up front so a typo doesn’t silently produce an empty env value at run time.
Variables & requires
task <T> requires variable <V> to be set
A requires.vars: entry is missing. Built-in variables (GIT_*, TASK_FILE_DIR) satisfy the requirement even when their resolved value is empty — for instance, requires: { vars: [GIT_TAG] } is satisfied outside of a tagged commit.
Fix: set the variable in vars:, in env:, or pass it via a sub-task call site.
task <T> requires environment variable <E> to be set
A requires.env: entry is unset in the process environment (OS env + global dotenv). Per-task env: does not satisfy the requirement; the check runs against os.LookupEnv on purpose, so CI-only variables can be enforced cleanly.
resolving variable (sh: <cmd>): …
A vars: { X: { sh: <cmd> } } shell command failed. The wrapped error is the shell’s own.
Fix: run the command yourself — the failure mode is the same. Common cause: depending on a tool that isn’t installed on a clean machine.
Sources & checksums
cyclic source preset <X> (chain: a -> b -> a)
A user-defined entry in the top-level sources: map references itself transitively. The chain in the message tells you exactly where to break it.
resolving sources for task <T>: …
Almost always wraps a cyclic-preset error.
computing sources checksum: …
Filesystem failure while reading a source file (permissions, disappeared between glob and read, etc.). The wrapped error names the file.
Task cycles
task cycle involving "X" and "Y" means active task calls would wait on each
other. Break the dependency cycle, including references through aliases or
wildcards. Non-memoized task: calls may recurse with changing vars or env;
more than 100 nested calls fails with a task-call-depth error instead of
exhausting the stack.
Preconditions
task <T>: <msg>
A preconditions[] entry that declared its own msg: failed. The task name is preserved so you can find the source quickly in larger files.
task <T>: precondition failed: <sh>
A bare-string precondition failed. The shell command itself is shown verbatim — that’s the no-msg: fallback.
Fix: add a msg: to the precondition for a clearer error, or fix the underlying check.
Watch mode
task <T> has no sources, cannot watch
gogo -w <task> requires the task (or one of its transitive dependencies) to declare sources: so the watcher knows what to poll. Sources are collected recursively across deps:, so adding sources: on a leaf task is usually enough.
watch interval must be at least <d>
The interval: setting is below gogo’s floor. Bump it; the floor exists to keep CPU/IO use reasonable on large repos.
invalid interval <X>: …
The interval is not a valid Go duration string. Use values like 100ms, 500ms, 1s, 2s.
1Password / op://
uses op:// secrets but the 1Password CLI (op) is not installed: …
Some part of the resolved environment contained an op:// URI (either inline in task.env, dotenv-sourced, or via secrets:), but op is not on PATH. gogo wraps the command with op run only when needed; the check fires only on the affected command.
Fix: install op from https://developer.1password.com/docs/cli/get-started/, or stub the value in local development by overriding the env-var name in env: (since secrets: always wins, you’ll need to comment out the secrets: reference for that local override to take effect).
Aliases & resolution
alias <A> is defined by both <T1> and <T2>
Two tasks declared the same aliases: entry. Aliases share a flat global namespace with task names, so collisions must be unique across all included files.
task <T> not found
The task name (or alias) doesn’t resolve. Things to check, in order:
- Typo in the task name.
- Forgotten namespace prefix when calling from outside the include’s directory (
backend:build, notbuild). - The task is defined in a file gogo never loaded — usually a missing
includes:orflatten:entry.
When the unqualified name you typed matches the local segment of one or more namespaced tasks — e.g. gogo dev in a parent that only defines frontend:dev and backend:dev — gogo lists just those candidates instead of the whole index, so you can pick the sub-project you meant. If nothing matches, the full task list is printed as before.
See also
- CLI Reference —
--dryand--forcesemantics for reproducing failures without side effects. - Variables — the canonical resolution and precedence chains, useful when a value resolves to something unexpected.
- Secrets — full op:// flow.