{"record":{"id":"d3738450b4a178a2","repo":"apify/crawlee","slug":"the-state-conversion-for-persiststatekey-vali","errorCode":null,"errorMessage":"The state conversion for '${persistStateKey}' validated asynchronously, which this caller cannot await.","messagePattern":"The state conversion for '(.+?)' validated asynchronously, which this caller cannot await\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/recoverable_state.ts","lineNumber":46,"sourceCode":"/**\n * Applies a {@apilink SyncStateConversion}, throwing a {@apilink StateValidationError} for a schema that rejects\n * the value.\n *\n * @internal\n */\nexport function convertStateSync<TFrom, TTo>(\n    conversion: SyncStateConversion<TFrom, TTo>,\n    value: TFrom,\n    persistStateKey: string,\n): TTo {\n    if (typeof conversion === 'function') {\n        return conversion(value);\n    }\n\n    const result = conversion['~standard'].validate(value);\n\n    if ('then' in result) {\n        throw new Error(\n            `The state conversion for '${persistStateKey}' validated asynchronously, which this caller cannot await.`,\n        );\n    }\n\n    if (result.issues) {\n        throw new StateValidationError(persistStateKey, result.issues);\n    }\n\n    return result.value;\n}\n\nexport interface RecoverableStatePersistenceOptions {\n    /**\n     * The key under which the state is stored in the KeyValueStore\n     */\n    persistStateKey: string;\n\n    /**","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/apify/crawlee/blob/dbe57fb09ca607ad59dcf998f3925ef9ac3bb26c/packages/core/src/recoverable_state.ts#L28-L64","documentation":"RecoverableState validates its persisted state through a Standard Schema converter, but convertStateSync only supports validators whose validate() returns results synchronously. If the schema's validate() returned a Promise (detected via 'then' in result), the synchronous callers (#resolveDefaultStateExtension, #restoreStateExtension, #serializeStateExtension) cannot await it, so it throws rather than silently skipping validation.","triggerScenarios":"Providing a conversion/schema (e.g. an async Standard Schema implementation or a zod schema behind an async adapter) whose `~standard.validate` returns a thenable, then loading/serializing the RecoverableState (initialize/serialize paths).","commonSituations":"Using a schema library configured for async validation (async refinements/transforms); wrapping the converter so validate returns a Promise; switching schema implementations while keeping the sync recovery path.","solutions":["Replace the schema with a purely synchronous one (no async refinements/transforms) for the given persistStateKey.","Remove async validation logic (e.g. z.string().refine(async ...) or async superRefinement) from the state schema.","Pre-validate the value synchronously before handing it to RecoverableState.","If async validation is unavoidable, perform it yourself before/around state restore instead of relying on the sync converter."],"exampleFix":"// before\nconst schema = z.object({ at: z.string() }).refine(async (v) => checkRemote(v)); // async validate\n// after\nconst schema = z.object({ at: z.string() }).refine((v) => !Number.isNaN(Date.parse(v.at))); // sync validate","handlingStrategy":"validation","validationCode":"// Ensure the schema validates synchronously before handing it to RecoverableState\nconst result = schema['~standard'].validate(value);\nif (result instanceof Promise || 'then' in (result as any)) {\n  throw new Error('State schema must validate synchronously (no async refinements)');\n}","typeGuard":"function isSyncStandardSchema<T>(s: unknown): s is StandardSchemaV1<T> {\n  try {\n    const r = (s as any)['~standard'].validate(undefined);\n    return !(r instanceof Promise) && !('then' in r);\n  } catch { return false; }\n}","tryCatchPattern":"try {\n  await state.initialize();\n} catch (err) {\n  if ((err as Error).message.includes('validated asynchronously')) {\n    throw new Error(`Schema for '${persistStateKey}' uses async validation; make it synchronous`);\n  }\n  throw err;\n}","preventionTips":["Avoid async refinements/transforms in persisted-state schemas.","Prefer synchronous schema libraries or sync mode for state validation.","Test state schemas with validate() and assert the result is not a Promise.","Do heavy async checks outside the schema, before state restore."],"tags":["validation","async","schema","recoverable-state"],"backgroundTag":"async-validation-not-supported","analyzedSha":"dbe57fb09ca607ad59dcf998f3925ef9ac3bb26c","analyzedAt":"2026-08-30T22:22:28.328Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}