different-ai/openwork · error · InterpreterRuntimeError
Property '${key}' is not available in CodeMode.
Error message
Property '${key}' is not available in CodeMode. What it means
guardedSet is used by Object.assign and Object.fromEntries in CodeMode to block writing properties whose keys match isBlockedMember (a denylist of dangerous names like __proto__, constructor, prototype). Writing such a key throws this error to prevent prototype-pollution-style attacks inside the sandbox.
Source
Thrown at packages/codemode/src/stdlib/object.ts:19
import { type AstNode, InterpreterRuntimeError } from "../interpreter/model.js"
import { isBlockedMember } from "../tool-runtime.js"
import { isSandboxValue, SandboxMap, SandboxURLSearchParams } from "../values.js"
import { boundedData, coerceToString } from "./value.js"
export const objectStatics = new Set(["keys", "values", "entries", "hasOwn", "assign", "fromEntries"])
export const invokeObjectMethod = (name: string, args: Array<unknown>, node: AstNode): unknown => {
if (!objectStatics.has(name)) throw new InterpreterRuntimeError(`Object.${name} is not available in CodeMode.`, node)
const requireObject = (): Record<string, unknown> => {
const value = boundedData(args[0], `Object.${name} input`)
if (isSandboxValue(value)) return {}
if (value === null || typeof value !== "object" || Array.isArray(value)) {
throw new InterpreterRuntimeError(`Object.${name} expects a data object.`, node)
}
return value as Record<string, unknown>
}
const guardedSet = (out: Record<string, unknown>, key: string, item: unknown): void => {
if (isBlockedMember(key)) throw new InterpreterRuntimeError(`Property '${key}' is not available in CodeMode.`, node)
out[key] = item
}
switch (name) {
case "keys": {
const value = boundedData(args[0], "Object.keys input")
if (isSandboxValue(value)) return []
if (Array.isArray(value)) return Object.keys(value)
if (value === null || typeof value !== "object") {
throw new InterpreterRuntimeError("Object.keys expects a data object or array.", node)
}
return Object.keys(value)
}
case "values":
return Object.values(requireObject())
case "entries":
return Object.entries(requireObject()).map(([key, item]) => [key, item])
case "hasOwn":
return Object.hasOwn(requireObject(), String(args[1]))View on GitHub (pinned to 2b7df46e8a)
Solutions
- Sanitize input keys before calling assign/fromEntries: drop or rename keys matching /^( __proto__|constructor|prototype)$/
- Use a prefix or namespaced keys for untrusted data, e.g. store as meta['field'] instead of raw keys
- Filter pairs: pairs.filter(([k]) => k !== '__proto__' && k !== 'constructor' && k !== 'prototype')
- If the key is legitimately needed, transform it (e.g. underscore prefix) before constructing the object
Example fix
// before
const merged = Object.assign({}, userInput)
// after
const safe = Object.fromEntries(
Object.entries(userInput).filter(([k]) => !['__proto__','constructor','prototype'].includes(k))
)
const merged = Object.assign({}, safe) Defensive patterns
Strategy: validation
Validate before calling
const BLOCKED = new Set(['__proto__','constructor','prototype']) const sanitized = Object.fromEntries( pairs.filter(([k]) => !BLOCKED.has(String(k))) )
Try / catch
try {
return Object.assign({}, untrusted)
} catch (e) {
if (e instanceof InterpreterRuntimeError && e.message.includes("is not available in CodeMode") && e.message.includes("Property")) {
return Object.assign({}, filterBlockedKeys(untrusted))
}
throw e
} Prevention
- Filter __proto__/constructor/prototype keys from any untrusted input
- Namespace untrusted payload keys before merging
- Never merge raw user/API key-value data blindly
- Fuzz your merge paths with payloads containing dangerous keys
When it happens
Trigger: Object.assign(target, {__proto__: x}), Object.fromEntries([['__proto__', {}]]), Object.fromEntries([['constructor', fn]]), or merging user/API-supplied key/value data that contains keys named __proto__, prototype, or constructor.
Common situations: Merging untrusted API/JSON payloads into config objects where a payload key collides with a blocked name; CSV/JSON ingest where a column is literally named __proto__.
Related errors
- Object.${name} is not available in CodeMode.
- Object.${name} expects a data object.
- Object.keys expects a data object or array.
- Object.assign expects data objects.
- Object.fromEntries expects an array of [key, value] pairs.
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/bf60cda758a63db9.
Report an issue: GitHub.