{"record":{"id":"0c24da1efa1ebf08","repo":"farion1231/cc-switch","slug":"openclaw-env-object-required","errorCode":"OPENCLAW_ENV_OBJECT_REQUIRED","errorMessage":"OPENCLAW_ENV_OBJECT_REQUIRED","messagePattern":"OPENCLAW_ENV_OBJECT_REQUIRED","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/components/openclaw/utils.ts","lineNumber":30,"sourceCode":"];\n\nexport const OPENCLAW_UNSUPPORTED_PROFILE = \"__unsupported_profile__\";\nexport const OPENCLAW_UNSET_PROFILE = \"__unset_profile__\";\n\nexport function parseOpenClawEnvEditorValue(raw: string): OpenClawEnvConfig {\n  if (!raw.trim()) {\n    throw new Error(\"OPENCLAW_ENV_EMPTY\");\n  }\n\n  let parsed: unknown;\n  try {\n    parsed = JSON.parse(raw);\n  } catch {\n    throw new Error(\"OPENCLAW_ENV_INVALID_JSON\");\n  }\n\n  if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n    throw new Error(\"OPENCLAW_ENV_OBJECT_REQUIRED\");\n  }\n  return parsed as OpenClawEnvConfig;\n}\n\nexport function isOpenClawToolsProfile(\n  profile?: string,\n): profile is OpenClawToolsProfile {\n  return (\n    typeof profile === \"string\" &&\n    OPENCLAW_TOOL_PROFILES.includes(profile as OpenClawToolsProfile)\n  );\n}\n\nexport function getOpenClawToolsProfileSelectValue(profile?: string): string {\n  if (!profile) {\n    return OPENCLAW_UNSET_PROFILE;\n  }\n  return isOpenClawToolsProfile(profile)","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/farion1231/cc-switch/blob/0b5da510168914b251481654a568c3ffacd62cf4/src/components/openclaw/utils.ts#L12-L48","documentation":"Thrown when the env editor string parses as valid JSON but the result is not a plain object — null, a number, a string, a boolean, or an array are all rejected before the value is cast via 'parsed as OpenClawEnvConfig'. This guard protects that downstream cast from receiving a non-indexable value. It is the last of three gates, after OPENCLAW_ENV_EMPTY and OPENCLAW_ENV_INVALID_JSON.","triggerScenarios":"Input such as 'null', '[1,2]', '\"coding\"', or '42' — valid JSON whose top-level value is not an object.","commonSituations":"User wraps the config in quotes or brackets; pasting a JSON array of profiles; deleting the outer { } while editing.","solutions":["Wrap the intended key/value pairs in an object literal { ... }","Pre-check the parsed value with a plain-object type guard before calling the parser","Show a live preview of the parsed top-level type in the editor UI"],"exampleFix":"// before\nconst env = parseOpenClawEnvEditorValue(raw); // raw = '[\"coding\"]' throws\n\n// after\nconst value: unknown = JSON.parse(raw);\nif (!isPlainObject(value)) {\n  showEditorError('Env config must be a JSON object');\n  return;\n}\nconst env = parseOpenClawEnvEditorValue(raw);","handlingStrategy":"type-guard","validationCode":"const value: unknown = JSON.parse(raw);\nif (!isPlainObject(value)) {\n  showEditorError('Env config must be a JSON object');\n  return;\n}\nconst env = parseOpenClawEnvEditorValue(raw);","typeGuard":"function isPlainObject(value: unknown): value is Record<string, unknown> {\n  return typeof value === 'object' && value !== null && !Array.isArray(value);\n}","tryCatchPattern":"try {\n  const env = parseOpenClawEnvEditorValue(raw);\n} catch (error) {\n  if (error instanceof Error && error.message === 'OPENCLAW_ENV_OBJECT_REQUIRED') {\n    // hint: wrap the config in { ... }\n  } else {\n    throw error;\n  }\n}","preventionTips":["Show a live preview of the parsed top-level type (object/array/scalar) in the editor","Reject arrays and quoted strings visually before submit","Reuse one isPlainObject guard for all JSON-object validations"],"tags":["openclaw","json","type-validation","env-config"],"backgroundTag":"schema-validation-failed","analyzedSha":"0b5da510168914b251481654a568c3ffacd62cf4","analyzedAt":"2026-08-20T14:29:00.113Z","contentChangedAt":"2026-08-20T14:29:00.113Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}