FoundationAgents/MetaGPT · error · ValueError
Moderator's instructions must include save or poison keyword
Error message
Moderator's instructions must include save or poison keyword
What it means
In the werewolf (Wolf) game, the Witch role decides its action by keyword-matching the Moderator's encrypted instruction: content containing 'save' selects Save(), 'poison' selects Poison(). If the restricted message from the Moderator contains neither keyword (case-insensitive), this ValueError is raised. The design is a documented FIXME: it depends on the Moderator's prompt wording.
Source
Thrown at metagpt/ext/werewolf/roles/witch.py:28
special_action_names: list[str] = ["Save", "Poison"]
async def _think(self):
"""女巫涉及两个特殊技能,因此在此需要改写_think进行路由"""
news = self.rc.news[0]
assert news.cause_by == any_to_str(InstructSpeak) # 消息为来自Moderator的指令时,才去做动作
if not news.restricted_to:
# 消息接收范围为全体角色的,做公开发言(发表投票观点也算发言)
self.rc.todo = Speak()
elif self.profile in news.restricted_to:
# FIXME: hard code to split, restricted为"Moderator"或"Moderator,角色profile"
# Moderator加密发给自己的,意味着要执行角色的特殊动作
# 这里用关键词进行动作的选择,需要Moderator侧的指令进行配合
if "save" in news.content.lower():
self.rc.todo = Save()
elif "poison" in news.content.lower():
self.rc.todo = Poison()
else:
raise ValueError("Moderator's instructions must include save or poison keyword")
return True
View on GitHub (pinned to 11cdf466d0)
Solutions
- Keep the literal English keywords 'save' or 'poison' in any customized Moderator instruction aimed at the Witch.
- If localizing, add the localized keywords to the branch checks or match on both.
- As a defensive patch, default to a no-op (e.g. Speak()) instead of raising when no keyword matches.
Example fix
# before
if "save" in news.content.lower():
self.rc.todo = Save()
elif "poison" in news.content.lower():
self.rc.todo = Poison()
else:
raise ValueError("Moderator's instructions must include save or poison keyword")
# after (also accept localized keywords, no raise)
content = news.content.lower()
if "save" in content or "救人" in content:
self.rc.todo = Save()
elif "poison" in content or "毒" in content:
self.rc.todo = Poison()
else:
self.rc.todo = Speak() Defensive patterns
Strategy: validation
Validate before calling
def witch_action_from(content: str):
c = content.lower()
if "save" in c:
return Save()
if "poison" in c:
return Poison()
return None # caller decides default instead of crashing Try / catch
try:
await witch.handle(msg)
except ValueError as e:
if "save or poison keyword" in str(e):
logger.warning("moderator instruction lacked witch keyword: %s", msg.content)
return # tolerate and continue the game
raise Prevention
- Treat moderator prompts as a contract: keep English keywords in all localizations.
- Test custom werewolf prompts against the witch keyword branches.
When it happens
Trigger: The Moderator sends a Witch-targeted restricted message whose content lacks the substrings 'save' or 'poison' — e.g. localized/translated prompts, reworded moderator instructions, or words like 'rescue'/'venom'.
Common situations: Customizing werewolf prompts (especially translating to non-English) without keeping the English keywords; upgrading MetaGPT where moderator prompt wording drifted; messages that merely mention the words in an unrelated form.
Related errors
AI-assisted analysis of FoundationAgents/MetaGPT@11cdf466d0 (2026-08-14).
Data as JSON: /api/errors/84783ae774d21fe2.
Report an issue: GitHub.