shareAI-lab/learn-claude-code · error · ValueError
Dependency not found: {dependency}
Error message
Dependency not found: {dependency} What it means
create_task(blockedBy=[...]) validates every dependency ID by calling _task_path(dependency).is_file() — the dependency's JSON must already exist in .tasks/. This prevents tasks from referencing nonexistent predecessors, which would deadlock scheduling since can_start() waits on those dependencies completing.
Source
Thrown at s13_agent_teams/code.py:142
if not isinstance(task_id, str) or not TASK_ID_PATTERN.fullmatch(task_id):
raise ValueError(f"Invalid task ID: {task_id!r}")
path = (TASKS_DIR / f"{task_id}.json").resolve()
if (not TASKS_ROOT.is_relative_to(WORKDIR.resolve())
or not path.is_relative_to(TASKS_ROOT)):
raise ValueError(f"Invalid task ID: {task_id!r}")
return path
def create_task(subject: str, description: str = "",
blockedBy: list[str] | None = None) -> Task:
subject = subject.strip()
if not subject:
raise ValueError("Task subject cannot be empty")
dependencies = list(dict.fromkeys(blockedBy or []))
with task_store_lock():
for dependency in dependencies:
if not _task_path(dependency).is_file():
raise ValueError(f"Dependency not found: {dependency}")
for _ in range(100):
task = Task(
id=f"task_{secrets.token_hex(4)}",
subject=subject,
description=description,
status="pending",
owner=None,
blockedBy=dependencies,
)
try:
with _task_path(task.id).open("x", encoding="utf-8") as handle:
json.dump(asdict(task), handle, indent=2)
return task
except FileExistsError:
continue
raise RuntimeError("Could not allocate a unique task ID")
View on GitHub (pinned to 985456f4ad)
Solutions
- Create dependency tasks first and use their returned Task.id values for blockedBy.
- Deduplicate/validate IDs against list_tasks() before calling create_task.
- In tests, build the dependency chain in order rather than in parallel threads.
Example fix
// before
create_task('deploy', blockedBy=['task_deadbeef']) // may not exist
// after
build = create_task('build')
deploy = create_task('deploy', blockedBy=[build.id]) Defensive patterns
Strategy: validation
Validate before calling
def deps_exist(dependency_ids: list[str]) -> bool:
from pathlib import Path
return all((TASKS_DIR / f'{d}.json').is_file() for d in dependency_ids)
# before create_task:
assert deps_exist(blockedBy or []) Try / catch
try:
task = create_task(subject, blockedBy=deps)
except ValueError as exc:
if str(exc).startswith('Dependency not found'):
deps = [d for d in deps if (TASKS_DIR / f'{d}.json').is_file()]
task = create_task(subject, blockedBy=deps) # or report upstream
else:
raise Prevention
- Create dependencies first and chain their returned .id values.
- Filter blockedBy against list_tasks() when IDs come from storage or user input.
- In tests, create the dependency graph sequentially.
When it happens
Trigger: create_task('x', blockedBy=['task_00000000']) when no such file exists; passing an ID with a typo; passing dependency IDs created in another workspace; a race where the dependency task was created but its file write failed.
Common situations: Copy-pasting task graphs between workspaces; races in tests that create dependent tasks concurrently; stale hardcoded IDs from a previous run (IDs are random hex per run).
Related errors
- Dependency not found: {dependency}
- Task subject cannot be empty
- Dependency not found: {dependency}
- Max 20 todos allowed
- Item {item_id}: text required
AI-assisted analysis of shareAI-lab/learn-claude-code@985456f4ad (2026-08-14).
Data as JSON: /api/errors/b20b171c7c667790.
Report an issue: GitHub.