smartcontractkit / smartcontractkit/cre-sdk-typescript

preHook makes every workflow fail with "Failed to parse configuration: Unexpected end of JSON input"

Open
#314 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
6
Forks
9
Avg merge
5h 23m
Merged PRs (30d)
6

Description

Summary

Any workflow that supplies hooks.preHook fails to execute with an error that points at the config
file. The config is irrelevant — an empty hook on an otherwise-working workflow reproduces it.

✗ workflow execution failed: Failed to parse configuration: Unexpected end of JSON input

Reproduction

On the stock hello-confidential-workflows-ts scaffold, change only the handler registration:

cre.handler(
  cronTrigger.trigger({ schedule: config.schedule }),
  () => 'probe',
  { preHook: () => ({}) },   // remove this line and the same workflow runs
)
cre workflow simulate fast --target staging-settings

Root cause

RunnerBase.newRunnerHelper parses the config on every phase, before it dispatches on
request.request.case:

// packages/cre-sdk/src/sdk/wasm/runner.ts
static async newRunnerHelper(newRunner, configHandlerParams) {
  hostBindings.versionV2()
  const request = RunnerBase.getRequest()
  const config = await configHandler(request, configHandlerParams)   // includes the preHook phase
  return newRunner(config, request)
}

and configHandler's default parser is JSON.parse(Buffer.from(request.config).toString()). The host
sends the preHook ExecuteRequest with an empty config, so this is JSON.parse('').

Either side can fix it: the host can populate config on preHook requests, or the SDK can skip config
parsing for that phase. Happy to open a PR for the SDK-side fix if that is the preferred direction —
I did not want to guess which of the two is intended.

What I ruled out

All of the following fail identically, so it is not the restriction contents, the TEE path, or my config:

  • a fully-populated RestrictionsJson built from cre.restrictors.EVMRestrictor's own
    limitCallContract / limitHeaderByNumber / limitWriteReport helpers
  • with and without maxTotalCalls
  • type set to CAPABILITY_RESTRICTION_TYPE_CLOSED and to ..._OPEN
  • cre.handlerInTee and plain cre.handler
  • --limits none
  • an empty hook returning {}

The returned object typechecks against RestrictionsJson in every case.

Impact

The pre-execution capability budget is exactly the control a confidential workflow most wants, since
it bounds what a compromised handler can do. We had to ship ours as an exported, unit-tested function
that is not wired in, with a comment explaining why.

Secondly, and worth separating from the bug itself: the error message cost far more than the bug
did.
"Failed to parse configuration" reads as your config file is malformed, so I spent over an
hour bisecting a valid config — deleting fields, shortening values, tuples versus arrays, measuring
byte sizes — and briefly concluded there was a config-size cliff. The reason that theory survived is
that a config which fails zod validation errors before the hook runs, so incomplete configs appear
to work and complete ones appear to break. Any error raised at hook-evaluation time, naming the hook,
would have made this a two-minute diagnosis.

Versions

  • @chainlink/cre-sdk 1.20.0 (also reproduced on 1.18.0)
  • cre CLI v1.32.0 (cre update reports it is the latest)
  • bun 1.4.2, Linux x64
  • template hello-confidential-workflows-ts

sdk/utils/config/index.js and sdk/wasm/runner.js are byte-identical between 1.18.0 and 1.20.0.
runner.ts was last touched in "Add prehook to the SDK" (2026-04-15), so this appears to have been
present since the feature landed.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with packages/cre-sdk/src/sdk/wasm/runner.ts, especially RunnerBase.newRunnerHelper, and compare its phase dispatch with the default parser in sdk/utils/config/index.js. Reproduce with cre workflow simulate fast --target staging-settings using the hello-confidential-workflows-ts scaffold; done means a workflow with an empty preHook executes without the JSON parsing error.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript, wasm
Domain
backend
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.