gastownhall/beads · error
unknown external type: %s
Error message
unknown external type: %s
What it means
evaluateExternal supports only two external check types: "file.exists" and "env". Any other Condition.ExternalType value falls through the switch and yields this error. ParseCondition is the only producer of external conditions and always sets one of the two valid values.
Source
Thrown at internal/formula/condition.go:412
path = strings.ReplaceAll(path, "{{"+k+"}}", v)
}
_, err := os.Stat(path)
exists := err == nil
return &ConditionResult{
Satisfied: exists,
Reason: fmt.Sprintf("file %q exists: %v", path, exists),
}, nil
case "env":
actual := os.Getenv(c.ExternalArg)
satisfied, reason := compare(actual, c.Operator, c.Value)
return &ConditionResult{
Satisfied: satisfied,
Reason: reason,
}, nil
}
return nil, fmt.Errorf("unknown external type: %s", c.ExternalType)
}
// Helper functions
func unquote(s string) string {
s = strings.TrimSpace(s)
if len(s) >= 2 {
if (s[0] == '\'' && s[len(s)-1] == '\'') || (s[0] == '"' && s[len(s)-1] == '"') {
return s[1 : len(s)-1]
}
}
return s
}
func getNestedValue(m map[string]interface{}, path string) interface{} {
if m == nil {
return nil
}View on GitHub (pinned to 71377f2769)
Solutions
- Use only ExternalType "file.exists" (with ExternalArg=path) or "env" (with ExternalArg=var name, Operator, Value)
- Build external conditions with formula.ParseCondition, e.g. ParseCondition("file.exists('go.mod')") or ParseCondition("env.CI == 'true'")
- If a new check type is needed, extend ParseCondition/evaluateExternal in the library rather than hand-setting ExternalType
Example fix
// before
cond := &formula.Condition{Type: formula.ConditionTypeExternal, ExternalType: "http.ok", ExternalArg: "https://..."}
res, err := cond.Evaluate(ctx) // unknown external type: http.ok
// after
cond, _ := formula.ParseCondition("file.exists('go.mod')")
res, err := cond.Evaluate(ctx) Defensive patterns
Strategy: validation
Validate before calling
func validExternalType(t string) bool { return t == "file.exists" || t == "env" }
if cond.Type == formula.ConditionTypeExternal && !validExternalType(cond.ExternalType) {
return fmt.Errorf("external type %q must be file.exists or env", cond.ExternalType)
} Type guard
func isKnownExternalType(t string) bool {
return t == "file.exists" || t == "env"
} Try / catch
res, err := cond.Evaluate(ctx)
if err != nil && strings.HasPrefix(err.Error(), "unknown external type") {
return fmt.Errorf("external check %q not supported; use file.exists or env", cond.ExternalType)
}
return res, err Prevention
- Express external checks only as file.exists('path') or env.VAR op 'value' condition strings
- Parse them with formula.ParseCondition instead of setting ExternalType manually
- If you need new probe types, extend the parser/evaluator in the library, not the struct
When it happens
Trigger: Evaluate() on a Type=external Condition whose ExternalType is empty or an arbitrary string (e.g. "http.ok", "cmd.exit") — only possible when the struct is built or mutated outside ParseCondition.
Common situations: Trying to add custom external probes (HTTP checks, command exits) by writing ExternalType directly instead of extending the parser; struct-literal construction with a forgotten ExternalType; version drift where a newer/older writer emitted an unsupported type.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- unknown condition type: %s
- unknown field: %s
- unknown aggregate function: %s
- parsing formula: %w
- resolving formula: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/04713daa00d5314e.
Report an issue: GitHub.