{"record":{"id":"04713daa00d5314e","repo":"gastownhall/beads","slug":"unknown-external-type-s","errorCode":null,"errorMessage":"unknown external type: %s","messagePattern":"unknown external type: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/formula/condition.go","lineNumber":412,"sourceCode":"\t\t\tpath = strings.ReplaceAll(path, \"{{\"+k+\"}}\", v)\n\t\t}\n\t\t_, err := os.Stat(path)\n\t\texists := err == nil\n\t\treturn &ConditionResult{\n\t\t\tSatisfied: exists,\n\t\t\tReason:    fmt.Sprintf(\"file %q exists: %v\", path, exists),\n\t\t}, nil\n\n\tcase \"env\":\n\t\tactual := os.Getenv(c.ExternalArg)\n\t\tsatisfied, reason := compare(actual, c.Operator, c.Value)\n\t\treturn &ConditionResult{\n\t\t\tSatisfied: satisfied,\n\t\t\tReason:    reason,\n\t\t}, nil\n\t}\n\n\treturn nil, fmt.Errorf(\"unknown external type: %s\", c.ExternalType)\n}\n\n// Helper functions\n\nfunc unquote(s string) string {\n\ts = strings.TrimSpace(s)\n\tif len(s) >= 2 {\n\t\tif (s[0] == '\\'' && s[len(s)-1] == '\\'') || (s[0] == '\"' && s[len(s)-1] == '\"') {\n\t\t\treturn s[1 : len(s)-1]\n\t\t}\n\t}\n\treturn s\n}\n\nfunc getNestedValue(m map[string]interface{}, path string) interface{} {\n\tif m == nil {\n\t\treturn nil\n\t}","sourceCodeStart":394,"sourceCodeEnd":430,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/formula/condition.go#L394-L430","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\ncond := &formula.Condition{Type: formula.ConditionTypeExternal, ExternalType: \"http.ok\", ExternalArg: \"https://...\"}\nres, err := cond.Evaluate(ctx) // unknown external type: http.ok\n// after\ncond, _ := formula.ParseCondition(\"file.exists('go.mod')\")\nres, err := cond.Evaluate(ctx)","handlingStrategy":"validation","validationCode":"func validExternalType(t string) bool { return t == \"file.exists\" || t == \"env\" }\nif cond.Type == formula.ConditionTypeExternal && !validExternalType(cond.ExternalType) {\n\treturn fmt.Errorf(\"external type %q must be file.exists or env\", cond.ExternalType)\n}","typeGuard":"func isKnownExternalType(t string) bool {\n\treturn t == \"file.exists\" || t == \"env\"\n}","tryCatchPattern":"res, err := cond.Evaluate(ctx)\nif err != nil && strings.HasPrefix(err.Error(), \"unknown external type\") {\n\treturn fmt.Errorf(\"external check %q not supported; use file.exists or env\", cond.ExternalType)\n}\nreturn res, err","preventionTips":["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"],"tags":["formula","external-check","condition-evaluation"],"backgroundTag":"invalid-enum-value","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}