{"record":{"id":"fcd36f266bdcb138","repo":"can1357/oh-my-pi","slug":"missing-required-destination-option-key","errorCode":null,"errorMessage":"Missing required destination option: ${key}","messagePattern":"Missing required destination option: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/blob-broker/uploader-runtime.ts","lineNumber":48,"sourceCode":"\treadonly remoteId?: string;\n}\n\n/** Explicit failure used for destinations that cannot be contacted safely. */\nexport class DestinationUnavailableError extends Error {\n\t/** Destination that is unavailable. */\n\treadonly destination: BlobDestinationId;\n\n\tconstructor(destination: BlobDestinationId, reason: string) {\n\t\tsuper(`${destination} is unavailable: ${reason}`);\n\t\tthis.name = \"DestinationUnavailableError\";\n\t\tthis.destination = destination;\n\t}\n}\n\n/** Read a required option without coercing its configured type. */\nexport function requireOption(config: DestinationRuntimeConfig, key: string): DestinationOptionValue {\n\tconst value = config.options[key];\n\tif (value === undefined) throw new Error(`Missing required destination option: ${key}`);\n\treturn value;\n}\n\n/** Read a string option, returning a fallback when it is absent. */\nexport function optionString(config: DestinationRuntimeConfig, key: string, fallback?: string): string | undefined {\n\tconst value = config.options[key];\n\tif (value === undefined) return fallback;\n\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}","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/blob-broker/uploader-runtime.ts#L30-L66","documentation":"requireOption() reads a value out of a destination runtime's options map and throws when the key is absent. It is the strict accessor for required destination configuration (e.g. bucket name, endpoint URL) — the runtime refuses to start with incomplete config rather than failing later mid-upload. Note it only checks undefined, so an explicitly-set null or empty string still passes through.","triggerScenarios":"Calling requireOption(config, key) — directly or via the value() helper — for a key the destination runtime needs, when the user's destination config (from the broker config JSON) omitted that option or spelled the key differently.","commonSituations":"User config missing a required field for an uploader destination (e.g. missing \"bucket\" or \"region\"); renamed option keys between versions so old config files no longer match; YAML/JSON typo in the key name.","solutions":["Add the missing option to the destination config under the exact key named in the message","Validate the full config against the destination's documented option schema before starting the runtime","Check for key renames after a version upgrade and migrate old config keys","If the option should be optional, switch the runtime code to optionString()/optionNumber() with a fallback instead of requireOption()"],"exampleFix":"// before: config.options lacks \"bucket\"\nconst bucket = requireOption(config, \"bucket\");\n// after: validate the whole config up front\nconst requiredKeys = [\"bucket\", \"region\"];\nconst missing = requiredKeys.filter((k) => config.options[k] === undefined);\nif (missing.length) throw new Error(`Destination config missing: ${missing.join(\", \")}`);\nconst bucket = requireOption(config, \"bucket\");","handlingStrategy":"validation","validationCode":"// validate destination options before constructing the runtime\nconst REQUIRED = [\"bucket\", \"region\"] as const;\nconst missing = REQUIRED.filter((k) => config.options[k] === undefined);\nif (missing.length > 0) {\n  throw new Error(`destination config missing required options: ${missing.join(\", \")}`);\n}","typeGuard":"function hasOption(config: DestinationRuntimeConfig, key: string): boolean {\n  return config.options[key] !== undefined;\n}","tryCatchPattern":"try {\n  const bucket = requireOption(config, \"bucket\");\n} catch (err) {\n  if (String(err.message).startsWith(\"Missing required destination option:\")) {\n    logger.error(\"destination config incomplete\", { key: \"bucket\", providedKeys: Object.keys(config.options) });\n  }\n  throw err;\n}","preventionTips":["Validate the entire destination config against a schema at load time","List required options per destination type in docs/config templates","Use optionString/optionNumber with fallbacks for genuinely optional keys","Migrate renamed option keys on version upgrades before requiring the new names"],"tags":["configuration","validation","blob-broker"],"backgroundTag":"missing-config-option","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}