{"record":{"id":"440b74c25ebf5466","repo":"remix-run/remix","slug":"context-property-name-must-be-a-string","errorCode":null,"errorMessage":"Context property name must be a string.","messagePattern":"Context property name must be a string\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/fetch-router/src/lib/request-context.ts","lineNumber":296,"sourceCode":"   * @param key The key to write\n   * @param value The value to write\n   * @param options Options for installing the value as a direct context property\n   */\n  set = <key extends object>(\n    key: key,\n    value: ContextValue<key>,\n    options?: { property: string },\n  ): void => {\n    if (options != null) {\n      this.#installContextProperty(key, options.property)\n    }\n\n    this.#contextMap.set(key, value)\n  }\n\n  #installContextProperty(key: object, property: string): void {\n    if (typeof property !== 'string') {\n      throw new Error('Context property name must be a string.')\n    }\n\n    if (property.length === 0) {\n      throw new Error('Cannot install an empty context property name.')\n    }\n\n    let formattedProperty = JSON.stringify(property)\n\n    let existingProperty = this.#contextPropertyKeys.get(key)\n    if (existingProperty != null && existingProperty !== property) {\n      throw new Error(\n        `Cannot install context property ${formattedProperty} because this context key already uses ${JSON.stringify(existingProperty)}.`,\n      )\n    }\n\n    let existingKey = this.#contextProperties.get(property)\n    if (existingKey != null) {\n      if (existingKey !== key) {","sourceCodeStart":278,"sourceCodeEnd":314,"githubUrl":"https://github.com/remix-run/remix/blob/9696913134be3a4423513d2775f7b31d6917c049/packages/fetch-router/src/lib/request-context.ts#L278-L314","documentation":"RequestContext lets middleware attach named properties via set(key, value, { property }). The property name must be a string so it can be installed on the context object; this error fires when the property option is a symbol, number, or other non-string value.","triggerScenarios":"ctx.set(key, value, { property: someSymbol }) or passing a numeric/undefined property option at runtime (e.g. from dynamic config).","commonSituations":"Programmatically deriving property names from data that isn't guaranteed to be a string; TS types not covering a JS call site.","solutions":["Coerce or validate the property name to a non-empty string before calling set","Use static string literals for property names where possible","Validate dynamic config keys with typeof checks before registering"],"exampleFix":"// before\nctx.set(key, value, { property: config.name })\n// after\nctx.set(key, value, { property: String(config.name) })","handlingStrategy":"validation","validationCode":"if (typeof property !== 'string' || property.length === 0) throw new TypeError('invalid property name')","typeGuard":"const isValidPropertyName = (v: unknown): v is string => typeof v === 'string' && v.length > 0","tryCatchPattern":null,"preventionTips":["Use string literals for context property names","Validate dynamic names before ctx.set"],"tags":["request-context","fetch-router","middleware"],"backgroundTag":"invalid-context-property","analyzedSha":"9696913134be3a4423513d2775f7b31d6917c049","analyzedAt":"2026-08-27T19:55:01.024Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}