Skip to content

Feature/workflow batch cache - #2730

Draft
rafel-roboflow wants to merge 6 commits into
mainfrom
feature/workflow-batch-cache
Draft

Feature/workflow batch cache#2730
rafel-roboflow wants to merge 6 commits into
mainfrom
feature/workflow-batch-cache

Conversation

@rafel-roboflow

@rafel-roboflow rafel-roboflow commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes a TypeError: unhashable type: 'list' (HTTP 500) in workflow output serialization.

In serialize_single_workflow_result_field
(inference/core/workflows/execution_engine/v1/executor/output_constructor.py), the
per-kind loop resolves the serializer key as:

kind_name = single_kind.name if isinstance(single_kind, Kind) else kind

When single_kind is a plain string rather than a Kind object, the else branch
assigns kind — the whole list — instead of single_kind, and
kinds_serializers.get() raises unhashable type: 'list', failing the entire
/workflows/run request.

The string-kind case is reachable whenever an output resolves to input-induced lineage
whose kind declarations are raw strings from the workflow JSON — e.g. an output whose
selector points at a WorkflowBatchInput. Concretely: any workflow that pre-computes a
block's outputs client-side and injects them as a WorkflowBatchInput (with the output
selector rewritten to that input) hits this on every run.

One-word fix: else single_kind. With it, string kinds resolve serializers normally, and
kinds without a registered serializer fall through to the existing raw-value passthrough
instead of crashing.

Related Issue(s): none filed — found while building block-output caching for Workflow
Builder previews (roboflow/roboflow), which rewrites cached blocks' output selectors to
injected WorkflowBatchInputs and hits this path on every cached image-preview run.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)

Testing

  • I have tested this change locally
  • I have added/updated tests for this change

Test details:

Reproduced against a local inference server with a workflow whose output selector points
at a WorkflowBatchInput (cached-block preview run from the Workflow Builder):
POST /workflows/run returned 500 with the traceback above. After the fix, the same
request serializes correctly and returns 200 with the expected outputs. No unit test
added — happy to add one exercising serialize_single_workflow_result_field with a
string kind if maintainers want it in this PR.

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code where necessary, particularly in hard-to-understand areas
  • My changes generate no new warnings or errors
  • I have updated the documentation accordingly (if applicable)

Additional Context

The bug is dormant in most workflows because kinds attached to step outputs arrive as
Kind objects — only the string-kind branch is affected, which is why it survived
unnoticed. Full traceback for searchability:

File ".../executor/output_constructor.py", line 509, in serialize_single_workflow_result_field
serializer = kinds_serializers.get(kind_name)
TypeError: unhashable type: 'list'

One honest gap flagged in the form: no unit test in the diff. If you want it bulletproof before review, say so — a ~10-line test on serialize_single_workflow_result_field with a string kind would pin it, and I can write it in your
inference checkout now.

while the stream runs one frame at a time; slice by frame_id so
batch lengths match the current image batch.
  serialize_single_workflow_result_field assigned the whole kind list
  instead of the current element when a kind is a plain string (not a
  Kind object), making kinds_serializers.get() throw
  "unhashable type: 'list'". String kinds occur for outputs resolving to
  WorkflowBatchInput lineage, e.g. selectors rewritten to injected batch
  inputs. Use the element; unknown kinds keep the existing raw-value
  fallback.
@github-actions

Copy link
Copy Markdown
Contributor

👋 Thanks for the pull request! Here is how automated Claude review works here, so you spend credits (and reviewer time) wisely.

🚧 Right now this is a draft, so automated Claude review is paused — nothing is being spent yet. Mark it Ready for review to trigger it.

Warning

💸 The Claude reviewer bills in credits, not vibes

Automated review spins up a real agent that reads real code and spends real credits on every pass. It is glad to help — but it is not a rubber duck, a linter you poke in a loop, or a substitute for reading the contributing guide. Treat it like an expensive senior reviewer whose time you booked, and show up prepared.

Draft when unsure, Ready when you mean it:

  • 🌱 Not sure the PR is in good shape yet? Keep it (or set it back) as a draft — drafts pause review, so you can push and iterate without burning credits on a moving target.
  • 💪 Feel strong about the contents? Mark it Ready for review and the reviewer will take a look.

However you get there, arrive prepared:

  • 🧱 Bring a SOLID, thorough PR. Point your local agent at our skills/ to tune it to our guidelines first — or, if you are one of those fabled carbon-based contributors, read them yourself. A half-baked diff costs exactly the same to review as a finished one.
  • Resolve every comment before you re-request review. Re-requesting with threads still open means paying twice for the same conversation.
  • 🔁 Do not use CI review as an inner loop for a local agent. The reviewer is not a step-by-step debugger — do the unfolding locally and arrive with the answer, not the search.
  • 🙋 If something looks off, ask a human. One question to a maintainer is cheaper and faster than three rounds of agent re-review chasing a misread.

Reviews are not free. A draft costs nothing to review; a Ready PR is a promise that it is worth reviewing.

  • Prefer to skip automated review entirely? Add the skip-claude-review label.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant