{"record":{"id":"0eefd8313786d39a","repo":"langgenius/dify","slug":"missing-required-deployment-binding","errorCode":null,"errorMessage":"Missing required deployment binding.","messagePattern":"Missing required deployment binding\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/features/deployments/create-guide/state/submission.ts","lineNumber":170,"sourceCode":"\n      if (!get(canDeployAtom)) return undefined\n\n      set(isCreatingDeploymentAtom, true)\n\n      try {\n        const selectedEnvironmentIdentifier = selectedEnvironmentId.trim()\n        const freshSelectedEnvironment =\n          selectedEnvironment ||\n          (selectedEnvironmentIdentifier\n            ? (await deployableEnvironmentsQuery.refetch()).data?.environments.find((environment) =>\n                environmentMatchesIdentifier(environment, selectedEnvironmentIdentifier),\n              )\n            : undefined)\n        const targetEnvironmentId = freshSelectedEnvironment?.id\n        if (!targetEnvironmentId)\n          throw new CreateDeploymentGuideSubmissionBlockedError('deployFailed')\n\n        if (!get(requiredBindingsReadyAtom)) throw new Error('Missing required deployment binding.')\n        if (!get(requiredEnvVarsReadyAtom))\n          throw new Error('Missing required deployment environment variable.')\n\n        const envVars = envVarSlots.flatMap((slot) => envVarInput(slot, envVarValues[slot.key]))\n        const commonDeploymentRequest = {\n          newAppInstance: {\n            displayName: submittedInstanceName,\n            description: get(instanceDescriptionAtom).trim() || undefined,\n          },\n          environmentId: targetEnvironmentId,\n          releaseName: submittedReleaseName,\n          releaseDescription: submittedReleaseDescription || undefined,\n          credentials: selectedDeploymentRuntimeCredentials(bindingSlots, bindingSelections),\n          envVars,\n          idempotencyKey: createDeploymentIdempotencyKey(),\n          expectedDslDigest: deploymentOptions?.dslDigest,\n        } satisfies Omit<DeployRequest, 'dsl' | 'sourceAppId'>\n        const deploymentRequest =","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/web/features/deployments/create-guide/state/submission.ts#L152-L188","documentation":"Thrown as a plain Error after the environment is resolved but before constructing the deployment request, when the requiredBindingsReadyAtom Jotai atom evaluates to false. This is a state-invariant violation: submission proceeded despite required service bindings (e.g. runtime credentials/binding slots) not being fully configured. It is intentionally a generic Error, not a typed sentinel, because it indicates a logic gap rather than a user action.","triggerScenarios":"Fires when bindingSlots contain entries whose bindingSelections are incomplete or invalid, causing requiredBindingsReadyAtom to be false at submit time. Concretely: a binding slot has no selected credential, or selectedDeploymentRuntimeCredentials returns an incomplete shape.","commonSituations":"The submit button is enabled by a canDeployAtom gate that is out of sync with requiredBindingsReadyAtom (stale derived state), a binding was cleared asynchronously after the gate check, or a newly added required binding slot was not yet satisfied.","solutions":["Audit canDeployAtom derivation to ensure it ANDs in requiredBindingsReadyAtom so submit is not invokable when bindings are incomplete.","Inspect bindingSlots and bindingSelections in DevTools to find which slot is reporting incomplete.","Add a UI-level error indicator per binding slot so the user sees what is missing before submit.","If the atom is genuinely stale, ensure atoms feeding requiredBindingsReadyAtom are reset on slot changes."],"exampleFix":"// before\nif (!get(requiredBindingsReadyAtom)) throw new Error('Missing required deployment binding.')\n\n// after - block at the gate so submit cannot fire\n// in canDeployAtom derivation:\n// export const canDeployAtom = atom((get) =>\n//   get(environmentSelectedAtom) && get(requiredBindingsReadyAtom) && get(requiredEnvVarsReadyAtom))","handlingStrategy":"validation","validationCode":"// Pre-check bindings readiness before allowing submit\nconst bindingsReady = useAtomValue(requiredBindingsReadyAtom)\nconst canSubmit = environmentSelected && bindingsReady\n// <button disabled={!canSubmit} />","typeGuard":"function areBindingsReady(slots: BindingSlot[], selections: Record<string, unknown>): boolean {\n  return slots.every((slot) => slot.optional || !!selections[slot.key])\n}","tryCatchPattern":"try {\n  await submit()\n} catch (e) {\n  if (e instanceof Error && e.message === 'Missing required deployment binding.') {\n    setBindingError('Please configure all required bindings.')\n    return\n  }\n  throw e\n}","preventionTips":["Derive canDeployAtom as the conjunction of all readiness atoms so submission is structurally blocked upstream.","Show per-binding-slot validation tied to the same derivation the gate uses.","Reset binding readiness atoms whenever bindingSlots change.","Add a unit test asserting canDeployAtom is false whenever requiredBindingsReadyAtom is false."],"tags":["frontend","deployment","state-management","jotai","invariant-violation"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}