{"record":{"id":"eb3009819f5d402f","repo":"sipeed/picoclaw","slug":"teams-webhook-at-least-one-webhook-target-is-requ","errorCode":null,"errorMessage":"teams_webhook: at least one webhook target is required","messagePattern":"teams_webhook: at least one webhook target is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/channels/teams_webhook/teams_webhook.go","lineNumber":67,"sourceCode":"\n// TeamsWebhookChannel is an output-only channel that sends messages\n// to Microsoft Teams via Power Automate workflow webhooks.\n// Multiple webhook targets can be configured and selected via ChatID.\ntype TeamsWebhookChannel struct {\n\t*channels.BaseChannel\n\tbc     *config.Channel\n\tconfig *config.TeamsWebhookSettings\n\tclient teamsMessageSender\n}\n\n// NewTeamsWebhookChannel creates a new Teams webhook channel.\nfunc NewTeamsWebhookChannel(\n\tbc *config.Channel,\n\tcfg *config.TeamsWebhookSettings,\n\tbus *bus.MessageBus,\n) (*TeamsWebhookChannel, error) {\n\tif len(cfg.Webhooks) == 0 {\n\t\treturn nil, fmt.Errorf(\"teams_webhook: at least one webhook target is required\")\n\t}\n\n\t// Require \"default\" webhook target\n\tif _, hasDefault := cfg.Webhooks[\"default\"]; !hasDefault {\n\t\treturn nil, fmt.Errorf(\"teams_webhook: a 'default' webhook target is required\")\n\t}\n\n\t// Validate all webhook targets have valid HTTPS URLs\n\tfor name, target := range cfg.Webhooks {\n\t\twebhookURL := target.WebhookURL.String()\n\t\tif webhookURL == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"teams_webhook: webhook %q has empty webhook_url\", name)\n\t\t}\n\t\tparsed, err := url.Parse(webhookURL)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"teams_webhook: webhook %q has invalid URL: %w\", name, err)\n\t\t}\n\t\tif !strings.EqualFold(parsed.Scheme, \"https\") {","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/channels/teams_webhook/teams_webhook.go#L49-L85","documentation":"NewTeamsWebhookChannel rejects a teams_webhook channel whose settings contain no webhook targets (config key webhooks, map[string]TeamsWebhookTarget, pkg/config/config.go:721). Like slack_webhook, the channel is outgoing-only and delivers exclusively via Microsoft Teams Workflows/Connectors incoming webhooks, so an empty map leaves nothing to send to and construction fails fast.","triggerScenarios":"Creating a channel of type teams_webhook with no webhooks: key, webhooks: {}, or entries indented under the wrong parent key so the map decodes empty; using teams_webhook when a two-way Teams bot channel was intended.","commonSituations":"Not having created the Teams incoming webhook URL (Power Automate Workflows 'When a webhook request is received' or legacy Office 365 connector) before configuring the channel; migrating from a single-url field to the webhooks map; YAML indentation mistakes after copy-pasting a slack_webhook block as a template.","solutions":["Create an incoming webhook in Teams (channel > Workflows/Connectors > incoming webhook) and copy the https://...webhook.office.com/... (or outlook.office365.com/webhook/...) URL.","Add it under webhooks with at least a default target — the constructor also requires a 'default' key and HTTPS URLs for every target.","Verify YAML nesting: webhooks sits under the channel's settings, each target is a map key with webhook_url.","If a full Teams bot (messages in, not just notifications out) is needed, use the teams channel type instead."],"exampleFix":"# before\nchannels:\n  msteams:\n    type: teams_webhook\n    settings: {}\n\n# after\nchannels:\n  msteams:\n    type: teams_webhook\n    settings:\n      webhooks:\n        default:\n          webhook_url: \"https://prod-XX.region.logic.azure.com/workflows/.../triggers/manual/paths/invoke\"","handlingStrategy":"validation","validationCode":"func teamsWebhookTargetsPresent(cfg *config.TeamsWebhookSettings) error {\n    if len(cfg.Webhooks) == 0 {\n        return fmt.Errorf(\"add webhooks.default.webhook_url (Teams Workflows URL) before enabling teams_webhook\")\n    }\n    return nil\n}","typeGuard":"// structural guard before construction\nfunc hasTeamsWebhookMap(v any) bool {\n    m, ok := v.(map[string]config.TeamsWebhookTarget)\n    return ok && len(m) > 0\n}","tryCatchPattern":"// Go: synchronous constructor error — validate config in the deploy pipeline; nothing to catch at message-send time","preventionTips":["Create the Teams Workflows/connector webhook URL first, then configure","Remember the 'default' target is also mandatory (companion validation)","teams_webhook is notification-only; pick the teams channel type for two-way bots"],"tags":["teams-webhook","config","channel-setup","startup"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}