Errors & debugging¶
Capy errors are designed to be actionable: each one tells you where the problem is, what the engine expected instead, and (when possible) a concrete fix to try.
Anatomy of a Capy error¶
error: function "service" arg "name": value "Bad Name!" does not match pattern for type "ServiceName"
hint: type "ServiceName" requires the value to match regex /^[a-z][a-z0-9-]{1,30}$/
3 │ service "Bad Name!" version "2.4.1"
│ ^
Four parts:
error: …— what went wrong, named in terms of the library's vocabulary (which function, which argument, which type).hint: …— how to fix it. For pattern violations the regex is shown; for option mismatches the valid options are listed; for typos the closest known name is suggested.<line> │ <source>— the offending line, verbatim.│ ^— a caret pointing at the column.
Three common errors, walked through¶
1. Unknown function (typo in DSL keyword)¶
error: no library function matches token "endpiont"
hint: did you mean "endpoint"?
1 │ endpiont GET "/users"
│ ^
The engine compared endpiont to every library function name
using Levenshtein distance. endpoint was within edit-distance 2,
so it was suggested. Fix: change endpiont → endpoint.
When no close match exists, the hint lists what is available:
error: no library function matches token "zzqq"
hint: library functions start with one of: endpoint, param, returns, api
2. Value violates a type's options enum¶
error: function "log_level" arg "lvl": value "verbose" is not in options for type "LogLevel"
hint: valid options: trace, debug, info, warn, error, fatal
The library declared:
verbose isn't on the list. The hint shows every valid value so
the author can pick one. When the value is close to a valid option,
did you mean ...? appears too:
error: function "env" arg "stage": value "prudo" is not in options for type "Env"
hint: did you mean "prod"? valid options: dev, staging, prod
3. Value violates a type's pattern regex¶
error: function "owner" arg "who": value "not-an-email" does not match pattern for type "Email"
hint: type "Email" requires the value to match regex /^[^@]+@[^@]+\.[^@]+$/
The hint includes the regex so authors can see what's wrong without opening the library.
4. Unknown type (typo in library)¶
Same Levenshtein-suggestion mechanism applied to the type table.
Source file location¶
Errors include the location in file:line:col format — same as
gcc, go, rustc, etc. Most editors recognize this and turn it into a
clickable link:
(The bare .Error() form. The CLI's prettier FormatWithSource
rendering with caret pointing is shown above.)
The capy check command¶
For library authoring, use capy check to validate without running
any source. It catches:
- Unknown types referenced by captures (with a "did you mean" hint).
- Block functions whose closer is missing.
- Conflicts where multiple functions try to match the same syntax.
$ capy check lib.capy
ok — 8 function(s), 7 type(s)
function service
function endpoint
...
type ServiceName
...
If something is wrong, the error is shown immediately:
$ capy check broken.capy
function "service" arg "name" capture has unknown type "ServiceNme"
hint: did you mean "ServiceName"?
When the error has no source¶
Some errors happen before the parser runs (library load failures,
file-not-found, malformed .capy). These don't have a line number
for your script — they're problems with the library or filesystem.
They're still wrapped in the same error: ... / hint: ... format
where helpful.
Debugging write blocks¶
When a write block or file_template produces unexpected output,
the typical mistakes are:
- Capturing a string but rendering without
unquote. Strings captured with typestringkeep their quotes. Use${name | unquote}to strip them for human-facing output. - Indent drift in multi-line backtick literals. Backtick
literals preserve newlines and indentation verbatim — every
leading space appears in the output. Use the
indent Nhelper on a sub-expression rather than visually indenting in source. - Forgetting a trailing newline.
write \foo`emitsfoo` with no terminator. End your literal with a literal newline if you want one.
Run with --out-dir and look at the generated files for multi-file
projects, or pipe to less for single-output.
Embedding-API errors¶
When using Capy from Go (capy.NewLibrary(...)), the same
*domain.CapyError is returned. You can type-assert it to render
your own UI:
out, err := lib.Run(source)
if err != nil {
if ce, ok := err.(*domain.CapyError); ok {
fmt.Printf("at line %d: %s\n", ce.Line, ce.Msg)
if ce.Hint != "" {
fmt.Printf(" → %s\n", ce.Hint)
}
} else {
fmt.Println("other error:", err)
}
}
domain.FormatWithSource(err, sourceString) is the same rendering
the CLI uses — drop it in any tool that wants the same look.
Reporting a confusing error¶
If you hit an error that should have a hint but doesn't, or whose
location is wrong: file an issue with the minimal lib.capy +
script.capy that reproduces it. The hint engine has grown
incrementally — every new "this would have been better as a hint"
becomes a one-line addition.