Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detect and report infinite loops #1652

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 28 additions & 5 deletions execution.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ def execute(self, prompt, prompt_id, extra_data={}, execute_outputs=[]):



def validate_inputs(prompt, item, validated):
def validate_inputs(prompt, item, validated, stack=[]):
unique_id = item
if unique_id in validated:
return validated[unique_id]
Expand All @@ -399,6 +399,22 @@ def validate_inputs(prompt, item, validated):
errors = []
valid = True

if unique_id in stack:
error = {
"type": "infinite_loop",
"message": "loop detected in workflow validation",
"details": f"detected at {unique_id}",
"extra_info": {"stack": f"{stack}"},
}
errors.append(error)
ret = (False, errors, unique_id)
validated[unique_id] = ret
# don't continue, because we're already here further up the stack
return ret

# add this node to the stack
stack.append(unique_id)

for x in required_inputs:
if x not in inputs:
error = {
Expand Down Expand Up @@ -450,7 +466,7 @@ def validate_inputs(prompt, item, validated):
errors.append(error)
continue
try:
r = validate_inputs(prompt, o_id, validated)
r = validate_inputs(prompt, o_id, validated, stack)
if r[0] is False:
# `r` will be set in `validated[o_id]` already
valid = False
Expand Down Expand Up @@ -577,13 +593,18 @@ def validate_inputs(prompt, item, validated):
errors.append(error)
continue

# pop the node back off the stack:
stack.pop()

if len(errors) > 0 or valid is not True:
ret = (False, errors, unique_id)
else:
ret = (True, [], unique_id)

validated[unique_id] = ret
return ret
# if we had a loop, unique_id will have been marked invalid further down the tree
if unique_id not in validated:
validated[unique_id] = ret
return validated[unique_id]

def full_type_name(klass):
module = klass.__module__
Expand Down Expand Up @@ -615,7 +636,7 @@ def validate_prompt(prompt):
valid = False
reasons = []
try:
m = validate_inputs(prompt, o, validated)
m = validate_inputs(prompt, o, validated, [])
valid = m[0]
reasons = m[1]
except Exception as ex:
Expand Down Expand Up @@ -659,6 +680,8 @@ def validate_prompt(prompt):
print(f"* {class_type} {node_id}:")
for reason in reasons:
print(f" - {reason['message']}: {reason['details']}")
if 'extra_info' in reason:
print(f" - {reason['extra_info']}")
node_errors[node_id]["dependent_outputs"].append(o)
print("Output will be ignored")

Expand Down