deepset-ai/haystack · error · ValueError
Invalid hook point '{hook_point}'. Valid hook points are: {'
Error message
Invalid hook point '{hook_point}'. Valid hook points are: {', '.join(VALID_HOOK_POINTS)}. What it means
FileSystemSkillStore parses YAML frontmatter from each skill's markdown file during warm_up/load_skill via _parse_frontmatter. This ValueError is raised when yaml.safe_load on the frontmatter block (content between --- delimiters) raises yaml.YAMLError, meaning the frontmatter is syntactically invalid YAML. The original YAMLError is chained so its message (with line/column info) is appended.
Source
Thrown at haystack/components/agents/agent.py:123
return {name for name, p in sig.parameters.items() if p.kind != inspect.Parameter.VAR_KEYWORD}
def _public_outputs(state: State) -> dict[str, Any]:
"""Return the State data excluding the internal state keys (i.e. the Agent's user-facing outputs)."""
return {key: value for key, value in state.data.items() if key not in _INTERNAL_STATE_KEYS}
def _validate_hooks(hooks: dict[HookPoint, list[Hook]]) -> None:
"""
Validate a hooks mapping: known hook points, real Hook objects, and hook-point restrictions.
:param hooks: Mapping of hook point to the hooks registered under it.
:raises ValueError: If a hook point is unknown, or a hook is registered under a hook point it does not support.
:raises TypeError: If a registered hook has no callable `run(state)`.
"""
for hook_point, hook_list in hooks.items():
if hook_point not in VALID_HOOK_POINTS:
raise ValueError(
f"Invalid hook point '{hook_point}'. Valid hook points are: {', '.join(VALID_HOOK_POINTS)}."
)
for h in hook_list:
if not callable(getattr(h, "run", None)):
if callable(h):
raise TypeError(
f"Hook registered for hook point '{hook_point}' is callable but is not a Hook object. "
"If it is a function, wrap it with the @hook decorator."
)
raise TypeError(
f"Hook registered for hook point '{hook_point}' must have a callable 'run(state)', "
f"got an object of type '{type(h).__name__}'."
)
# A hook may declare `allowed_hook_points` to restrict where it can run (e.g. ConfirmationHook only
# makes sense at "before_tool"). Hooks without it can be registered under any hook point.
allowed_points = getattr(h, "allowed_hook_points", None)
if allowed_points is not None and hook_point not in allowed_points:
raise ValueError(View on GitHub (pinned to e318778c9b)
Solutions
- Open the skill .md file named in the chained YAMLError message and fix the YAML syntax at the reported line/column (quote values containing colons, use spaces not tabs).
- Verify the file has exactly two '---' delimiter lines and that only YAML sits between them.
- Validate the frontmatter with python -c "import yaml,sys; yaml.safe_load(open('SKILL.md').read().split('---')[1])" before retrying.
Example fix
# before (SKILL.md frontmatter) --- name: my-skill description: Use this when: something happens --- # after --- name: my-skill description: "Use this when: something happens" ---
Defensive patterns
Strategy: validation
Validate before calling
import yaml
from pathlib import Path
def frontmatter_is_valid_yaml(skill_file: Path) -> bool:
lines = skill_file.read_text(encoding="utf-8").splitlines()
if not lines or lines[0].strip() != "---":
return False
try:
closing = lines.index("---", 1)
except ValueError:
return False
try:
yaml.safe_load("\n".join(lines[1:closing])) or {}
return True
except yaml.YAMLError:
return False Type guard
def is_valid_frontmatter_block(block: str) -> bool:
try:
return isinstance(yaml.safe_load(block) or {}, dict)
except yaml.YAMLError:
return False Try / catch
try:
store.load_skill(name)
except ValueError as e:
if "not valid YAML" in str(e):
logger.error("Fix YAML in skill file: %s", e)
raise Prevention
- Quote frontmatter values containing ':', '#', or '{' characters
- Use spaces, never tabs, for YAML indentation
- Lint all skill .md frontmatter with yamllint in CI before shipping
- Keep exactly two '---' delimiter lines and no stray ones in the body
When it happens
Trigger: Any skill .md file whose frontmatter block contains malformed YAML: unescaped colons in values, bad indentation, tabs instead of spaces, unclosed quotes or brackets, or a stray '---' split that puts non-YAML content into the block.
Common situations: Hand-edited SKILL.md files; copying a skill with a broken description containing ': ' or '#' unquoted; YAML tabs; editing on Windows leaving stray characters; a stray '---' line inside the skill text that mis-slices the block.
Related errors
- Hook registered for hook point '{hook_point}' is callable bu
- Skill frontmatter is opened with '---' but never closed with
- Hook of type '{type(h).__name__}' is registered under hook p
- Hook registered for hook point '{hook_point}' must have a ca
- {type(chat_generator).__name__} does not accept tools parame
AI-assisted analysis of deepset-ai/haystack@e318778c9b (2026-08-30).
Data as JSON: /api/errors/ff7a0243d0c55d22.
Report an issue: GitHub.