{"record":{"id":"c1a346e447803a29","repo":"can1357/oh-my-pi","slug":"destination-option-key-must-be-a-boolean","errorCode":null,"errorMessage":"Destination option ${key} must be a boolean","messagePattern":"Destination option (.+?) must be a boolean","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/blob-broker/uploader-runtime.ts","lineNumber":74,"sourceCode":"\tif (typeof value !== \"string\") throw new Error(`Destination option ${key} must be a string`);\n\treturn value;\n}\n\n/** Read a number option, returning a fallback when it is absent. */\nexport function optionNumber(config: DestinationRuntimeConfig, key: string, fallback?: number): number | undefined {\n\tconst value = config.options[key];\n\tif (value === undefined) return fallback;\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) {\n\t\tthrow new Error(`Destination option ${key} must be a finite number`);\n\t}\n\treturn value;\n}\n\n/** Read a boolean option, returning a fallback when it is absent. */\nexport function optionBoolean(config: DestinationRuntimeConfig, key: string, fallback?: boolean): boolean | undefined {\n\tconst value = config.options[key];\n\tif (value === undefined) return fallback;\n\tif (typeof value !== \"boolean\") throw new Error(`Destination option ${key} must be a boolean`);\n\treturn value;\n}\n\n/** Read a credential without exposing its value in an error. */\nexport function credentialString(config: DestinationRuntimeConfig, key: string): string | undefined {\n\tconst value = config.credentials[key];\n\treturn value === \"\" ? undefined : value;\n}\n\n/** Read a required credential without exposing its value in an error. */\nexport function requireCredential(config: DestinationRuntimeConfig, key: string): string {\n\tconst value = credentialString(config, key);\n\tif (value === undefined) throw new Error(`Missing required destination credential: ${key}`);\n\treturn value;\n}\n\n/** Select the injected request implementation, or Bun's global fetch by default. */\nexport function fetchFor(config: DestinationRuntimeConfig): FetchImpl {","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/blob-broker/uploader-runtime.ts#L56-L92","documentation":"optionBoolean reads a boolean destination option and throws when the value is defined but not a boolean. Flags like direct, isPublic, preview, raw, and requireDirectMode are used as strict booleans; the runtime refuses truthy strings such as \"yes\" or \"true\" instead of guessing. This keeps config semantics unambiguous.","triggerScenarios":"Calling optionBoolean(config, key) — via requireDirectMode, isPublic, s3Defaults, direct, preview, or raw — when config.options[key] is a string (\"true\", \"false\"), a number (0/1), or null-like non-boolean value.","commonSituations":"Writing `\"direct\": \"true\"` in JSON config, env-var-derived options that stay strings, or CLI overrides injected as strings into an options object.","solutions":["Use a real boolean literal in config: `\"direct\": true`.","Coerce env/CLI string values to booleans before building the options object (`value === \"true\"`).","Verify the option key is the correct one for this destination; some flags only exist on certain uploaders."],"exampleFix":"// before\n{ \"options\": { \"preview\": \"true\" } }\n// after\n{ \"options\": { \"preview\": true } }","handlingStrategy":"validation","validationCode":"function assertBooleanOption(options: Record<string, unknown>, key: string): void {\n  const v = options[key];\n  if (v !== undefined && typeof v !== \"boolean\") throw new Error(`option ${key} must be a boolean`);\n}\nassertBooleanOption(config.options, \"direct\");","typeGuard":"const isBoolean = (v: unknown): v is boolean => typeof v === \"boolean\";","tryCatchPattern":"try {\n  uploader = createUploader(config);\n} catch (err) {\n  if (String(err).includes(\"must be a boolean\")) config.options.direct = config.options.direct === \"true\";\n  else throw err;\n}","preventionTips":["Use true/false literals, never \"true\"/\"false\" strings, in config.","When importing from env vars, convert explicitly: process.env.FLAG === \"true\".","Validate the whole options object once at config load, not per uploader call."],"tags":["config","validation","type-error"],"backgroundTag":"invalid-config-option-type","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}