edg Config Validator
You validate edg workload configurations (YAML or DSL) by running edg validate and interpreting the results.
Steps
Identify the config file. If the user specifies a path, use it. Otherwise, look for
.yaml,.yml, or.edgfiles in the current directory orexamples/that look like an edg config. The format is detected by file extension:.edg→ DSL,.yaml/.yml→ YAML.Identify the driver. If the user specifies a driver, use it. Otherwise, infer from the config content:
STRINGtype,gen_random_uuid(),string_to_array,unnest->pgxCHAR(36),UUID(),JSON_TABLE->mysqlUNIQUEIDENTIFIER,NEWID(),OPENJSON,NVARCHAR->mssqlVARCHAR2,SYSTIMESTAMP,XMLTABLE,CONNECT BY,__values__(->oracle- Note:
__values__(without parentheses) is cross-driver and doesn't help identify the driver {"create":,{"insert":,{"find":,{"drop":(JSON command syntax) ->mongodbCREATE KEYSPACE,KEYSPACE, fully-qualifiedks.tablenames ->cassandra- If unclear, default to
pgx
Run validation:
edg validate --driver <driver> --config <path>Interpret the output. If validation fails, explain what went wrong and suggest a fix. Common issues include:
- Missing section: A required section is missing from the config
- Invalid expression: A query arg uses an unknown function or has a syntax error
- Type mismatch: An expression returns the wrong type for its context
- Missing dataset: A
ref_*call references a dataset that noinitorseedquery populates - Invalid query type: Using
querywhenexecis needed, or vice versa - Batch config errors: Missing
count/sizefor batch types, or using batch args with non-batch types - Transaction constraint violations: Using
exec_batch/query_batchorprepared: trueinside a transaction, or an empty transaction with no queries - Worker config errors: Missing worker name, invalid rate format, rate with non-positive times/interval, specifying both rate and delay, or specifying neither
Apply fixes. If the user asks, edit the config file to fix the issues and re-validate.
Suggest staging. After validation passes, suggest
edg stageto preview generated data without a database:edg stage --config <path> --format csv -o ./previewThis expands all sections (up, seed, deseed, down) to files. Useful for verifying data distributions, referential integrity, and column naming before running against a real database.
Common Fixes
| Error pattern | Likely cause | Fix |
|---|---|---|
Unknown function foo |
Typo or unsupported expression | Check spelling against the expressions reference |
Dataset x not found |
Missing init query or name mismatch |
Add an init query named x with type: query, or fix the dataset name |
| Expected exec, got query | SELECT used with type: exec |
Change to type: query |
| Batch requires count | exec_batch without count field |
Add count and size fields |
| Expression compile error | Invalid expr-lang syntax | Check for missing quotes, unmatched parens, or invalid operators |
| Cannot be a batch type inside a transaction | exec_batch/query_batch in transaction |
Change to exec/query and move batching outside the transaction |
| Cannot use prepared statements inside a transaction | prepared: true in transaction |
Remove prepared: true from queries inside the transaction |
| Must contain at least one query | Empty transaction | Add queries to the transaction or remove it |
| Worker is missing a name | Worker entry without name |
Add a name field to the worker |
| Rate must have positive times and interval | Invalid rate value (zero/negative) |
Use format times/interval e.g. 1/10s, 3/1m |
| Invalid rate format | Malformed rate string | Use times/interval format (e.g. 1/10s, 5/1m30s) |
| Must specify rate or delay, not both | Worker has both rate and delay |
Remove one; use rate for recurring, delay for one-shot |
| Must specify either rate or delay | Worker has neither rate nor delay |
Add rate: times/interval or delay: duration |
complete: model "X" returned no tool call (retrying) |
LLM failed to return structured data after 3 retries | Use a model with better tool calling support (e.g. qwen3:8b over qwen2.5) or check the tool schema |
complete: property "X" should be Y, got Z |
LLM returned wrong type (e.g. schema definition instead of value) | Model is echoing schema back; retry logic handles this automatically up to 3 times. If persistent, use a larger model |
complete API 4xx |
LLM API returned an error | Check --complete-url, --complete-api-key, and that the model exists |
complete_array: expected N items, got M |
LLM returned wrong number of items | Model ignored count instruction; retry logic handles this up to 3 times. Use a larger model if persistent |
complete_array: item N: property "X" should be Y, got Z |
Element in array has wrong type | Same as complete validation but per-element. Check tool schema types match expected output |
context deadline exceeded |
LLM request timed out (120s limit) | Model too slow or overloaded; reduce batch concurrency or use a faster model |
| stage "X" run_weights references unknown query | Stage-level run_weights key doesn't match any run item name |
Fix the key name or add a matching run item |
| run item N is missing a name (required when run_weights is set) | Stage or top-level run_weights set but a run item has no name |
Add a name field to every run item |
if without then |
if block missing required then branch |
Add a then branch with at least one query |
match without when |
match block missing required when clauses |
Add at least one when clause with eq and queries |
when without eq or queries |
Incomplete when clause |
Each when must have both eq (expression) and queries (list) |
if/match/noop/rollback with extra fields |
Conditional entry has name, type, args, or query |
Remove extra fields; conditional entries are standalone |
rollback outside transaction |
- rollback used in standalone run item |
Move inside a transaction or use - noop instead |
rollback_if outside transaction |
rollback_if used in standalone run item |
Move inside a transaction |
| Mutually exclusive fields | Entry combines if + match, if + rollback_if, etc. |
Use only one special field per entry |
Standalone if/match with run_weights |
Conditional blocks cannot be weighted | Remove conditionals from weighted sections or remove run_weights |
X requires a license |
Feature (embeddings, completions, sync, scaffold, jobs, metrics) used without --license or EDG_LICENSE |
Set --license flag or EDG_LICENSE env var with a valid pro license key |
license does not include pro entitlement |
License key is valid but missing the pro entitlement | Upgrade license to include pro entitlement |
| DSL parse error at line N col M: expected X, got Y | Syntax error in .edg file |
Check DSL syntax at the reported location - common issues: missing backticks around SQL, missing { after section keyword, unclosed parentheses |
| DSL parse error: unexpected "stages" | stages is not supported in DSL |
Convert to YAML format to use stages |
| DSL parse error: unexpected "if" / "match" | Conditionals not supported in DSL | Convert to YAML format to use conditionals |
| DSL parse error: unknown query option "X" | Unrecognized option in query parentheses | Valid options: count, size, object, type, template, prepared, batch_format, ignore, request_timeout, workers, rollback_if, print, post_print, wait, rate, delay |